mirror of
https://github.com/Samsung/escargot.git
synced 2026-06-22 10:01:50 +00:00
[return-check] change exception handling to return-check based method in interpreting (runtime) process
Signed-off-by: HyukWoo Park <hyukwoo.park@samsung.com>
This commit is contained in:
parent
da24cd6a2f
commit
26af0cddc6
94 changed files with 3129 additions and 1627 deletions
|
|
@ -528,14 +528,14 @@ typedef uint16_t LexicalBlockIndex;
|
|||
#endif
|
||||
|
||||
#ifdef STACK_GROWS_DOWN
|
||||
#define CHECK_STACK_OVERFLOW(state) \
|
||||
if (UNLIKELY(state.stackLimit() > (size_t)currentStackPointer())) { \
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, "Maximum call stack size exceeded"); \
|
||||
#define CHECK_STACK_OVERFLOW(state) \
|
||||
if (UNLIKELY(state.stackLimit() > (size_t)currentStackPointer())) { \
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::RangeError, "Maximum call stack size exceeded"); \
|
||||
}
|
||||
#else
|
||||
#define CHECK_STACK_OVERFLOW(state) \
|
||||
if (UNLIKELY(state.stackLimit() < (size_t)currentStackPointer())) { \
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, "Maximum call stack size exceeded"); \
|
||||
#define CHECK_STACK_OVERFLOW(state) \
|
||||
if (UNLIKELY(state.stackLimit() < (size_t)currentStackPointer())) { \
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::RangeError, "Maximum call stack size exceeded"); \
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -560,6 +560,9 @@ typedef uint16_t LexicalBlockIndex;
|
|||
#define REGEXP_CACHE_SIZE_MAX 64
|
||||
#endif
|
||||
|
||||
// represent that a function could throw an exception
|
||||
#define MAY_EXCEPTION
|
||||
|
||||
#include <tsl/robin_set.h>
|
||||
template <class Key, class Hash = std::hash<Key>,
|
||||
class KeyEqual = std::equal_to<Key>,
|
||||
|
|
|
|||
|
|
@ -3086,7 +3086,7 @@ void ExecutionStateRef::throwException(ValueRef* value)
|
|||
void ExecutionStateRef::checkStackOverflow()
|
||||
{
|
||||
ExecutionState& imp = *toImpl(this);
|
||||
CHECK_STACK_OVERFLOW(imp);
|
||||
// CHECK_STACK_OVERFLOW(imp);
|
||||
}
|
||||
|
||||
GCManagedVector<Evaluator::StackTraceData> ExecutionStateRef::computeStackTrace()
|
||||
|
|
@ -3201,6 +3201,11 @@ bool ValueRef::isUndefined()
|
|||
return toImpl(this).isUndefined();
|
||||
}
|
||||
|
||||
bool ValueRef::isException()
|
||||
{
|
||||
return toImpl(this).isException();
|
||||
}
|
||||
|
||||
bool ValueRef::isPointerValue()
|
||||
{
|
||||
return toImpl(this).isPointerValue();
|
||||
|
|
@ -3396,6 +3401,12 @@ ValueRef* ValueRef::createUndefined()
|
|||
.payload());
|
||||
}
|
||||
|
||||
ValueRef* ValueRef::createException()
|
||||
{
|
||||
return reinterpret_cast<ValueRef*>(EncodedValue(Value(Value::Exception))
|
||||
.payload());
|
||||
}
|
||||
|
||||
bool ValueRef::toBoolean(ExecutionStateRef* es)
|
||||
{
|
||||
return toImpl(this).toBoolean(*toImpl(es));
|
||||
|
|
|
|||
|
|
@ -939,12 +939,14 @@ public:
|
|||
}
|
||||
static ValueRef* createNull();
|
||||
static ValueRef* createUndefined();
|
||||
static ValueRef* createException();
|
||||
|
||||
bool isStoredInHeap();
|
||||
bool isBoolean();
|
||||
bool isNumber();
|
||||
bool isNull();
|
||||
bool isUndefined();
|
||||
bool isException();
|
||||
bool isInt32();
|
||||
bool isUInt32();
|
||||
bool isDouble();
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -30,14 +30,13 @@ namespace Escargot {
|
|||
static Value builtinArrayBufferConstructor(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (!newTarget.hasValue()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ConstructorRequiresNew);
|
||||
return Value();
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ConstructorRequiresNew);
|
||||
}
|
||||
|
||||
uint64_t byteLength = argv[0].toIndex(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (UNLIKELY(byteLength == Value::InvalidIndexValue)) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, state.context()->staticStrings().ArrayBuffer.string(), false, String::emptyString, ErrorObject::Messages::GlobalObject_FirstArgumentInvalidLength);
|
||||
return Value();
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::RangeError, state.context()->staticStrings().ArrayBuffer.string(), false, String::emptyString, ErrorObject::Messages::GlobalObject_FirstArgumentInvalidLength);
|
||||
}
|
||||
|
||||
Optional<uint64_t> maxByteLength;
|
||||
|
|
@ -45,15 +44,19 @@ static Value builtinArrayBufferConstructor(ExecutionState& state, Value thisValu
|
|||
if (UNLIKELY((argc > 1) && argv[1].isObject())) {
|
||||
Object* options = argv[1].asObject();
|
||||
Value maxLengthValue = options->get(state, ObjectPropertyName(state.context()->staticStrings().maxByteLength)).value(state, options);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (!maxLengthValue.isUndefined()) {
|
||||
maxByteLength = maxLengthValue.toIndex(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (UNLIKELY((maxByteLength.value() == Value::InvalidIndexValue) || (byteLength > maxByteLength.value()))) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, state.context()->staticStrings().ArrayBuffer.string(), false, String::emptyString, ErrorObject::Messages::GlobalObject_FirstArgumentInvalidLength);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::RangeError, state.context()->staticStrings().ArrayBuffer.string(), false, String::emptyString, ErrorObject::Messages::GlobalObject_FirstArgumentInvalidLength);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ArrayBufferObject::allocateArrayBuffer(state, newTarget.value(), byteLength, maxByteLength);
|
||||
ArrayBufferObject* result = ArrayBufferObject::allocateArrayBuffer(state, newTarget.value(), byteLength, maxByteLength);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
return result;
|
||||
}
|
||||
|
||||
// https://www.ecma-international.org/ecma-262/10.0/#sec-arraybuffer.isview
|
||||
|
|
@ -72,11 +75,11 @@ static Value builtinArrayBufferIsView(ExecutionState& state, Value thisValue, si
|
|||
}
|
||||
|
||||
|
||||
#define RESOLVE_THIS_BINDING_TO_ARRAYBUFFER(NAME, OBJ, BUILT_IN_METHOD) \
|
||||
if (UNLIKELY(!thisValue.isObject() || !thisValue.asObject()->isArrayBuffer() || thisValue.asObject()->isSharedArrayBufferObject())) { \
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().OBJ.string(), true, state.context()->staticStrings().BUILT_IN_METHOD.string(), ErrorObject::Messages::GlobalObject_CalledOnIncompatibleReceiver); \
|
||||
} \
|
||||
\
|
||||
#define RESOLVE_THIS_BINDING_TO_ARRAYBUFFER(NAME, OBJ, BUILT_IN_METHOD) \
|
||||
if (UNLIKELY(!thisValue.isObject() || !thisValue.asObject()->isArrayBuffer() || thisValue.asObject()->isSharedArrayBufferObject())) { \
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().OBJ.string(), true, state.context()->staticStrings().BUILT_IN_METHOD.string(), ErrorObject::Messages::GlobalObject_CalledOnIncompatibleReceiver); \
|
||||
} \
|
||||
\
|
||||
ArrayBuffer* NAME = thisValue.asObject()->asArrayBuffer();
|
||||
|
||||
// https://262.ecma-international.org/#sec-get-arraybuffer.prototype.bytelength
|
||||
|
|
@ -117,14 +120,15 @@ static Value builtinArrayBufferResize(ExecutionState& state, Value thisValue, si
|
|||
{
|
||||
RESOLVE_THIS_BINDING_TO_ARRAYBUFFER(obj, ArrayBuffer, resize);
|
||||
obj->throwTypeErrorIfDetached(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
if (!obj->isResizableArrayBuffer()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().ArrayBuffer.string(), true, state.context()->staticStrings().resize.string(), ErrorObject::Messages::GlobalObject_CalledOnIncompatibleReceiver);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().ArrayBuffer.string(), true, state.context()->staticStrings().resize.string(), ErrorObject::Messages::GlobalObject_CalledOnIncompatibleReceiver);
|
||||
}
|
||||
|
||||
double newByteLength = argv[0].toInteger(state);
|
||||
if (newByteLength < 0 || newByteLength > obj->maxByteLength()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, state.context()->staticStrings().ArrayBuffer.string(), true, state.context()->staticStrings().resize.string(), ErrorObject::Messages::GlobalObject_FirstArgumentInvalidLength);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::RangeError, state.context()->staticStrings().ArrayBuffer.string(), true, state.context()->staticStrings().resize.string(), ErrorObject::Messages::GlobalObject_FirstArgumentInvalidLength);
|
||||
}
|
||||
|
||||
obj->backingStore()->resize(static_cast<size_t>(newByteLength));
|
||||
|
|
@ -136,6 +140,7 @@ static Value builtinArrayBufferTransfer(ExecutionState& state, Value thisValue,
|
|||
{
|
||||
RESOLVE_THIS_BINDING_TO_ARRAYBUFFER(obj, ArrayBuffer, transfer);
|
||||
obj->throwTypeErrorIfDetached(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
double newByteLength = obj->byteLength();
|
||||
if (argc > 0 && !argv[0].isUndefined()) {
|
||||
|
|
@ -144,6 +149,7 @@ static Value builtinArrayBufferTransfer(ExecutionState& state, Value thisValue,
|
|||
|
||||
Value arguments[] = { Value(Value::DoubleToIntConvertibleTestNeeds, newByteLength) };
|
||||
ArrayBuffer* newValue = Object::construct(state, state.context()->globalObject()->arrayBuffer(), 1, arguments).asObject()->asArrayBuffer();
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// Let copyLength be min(newByteLength, O.[[ArrayBufferByteLength]]).
|
||||
// Perform CopyDataBlockBytes(toBlock, 0, fromBlock, 0, copyLength).
|
||||
|
|
@ -160,6 +166,7 @@ static Value builtinArrayBufferSlice(ExecutionState& state, Value thisValue, siz
|
|||
RESOLVE_THIS_BINDING_TO_ARRAYBUFFER(obj, ArrayBuffer, slice);
|
||||
|
||||
obj->throwTypeErrorIfDetached(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
double len = obj->byteLength();
|
||||
double relativeStart = argv[0].toInteger(state);
|
||||
|
|
@ -169,23 +176,29 @@ static Value builtinArrayBufferSlice(ExecutionState& state, Value thisValue, siz
|
|||
size_t newLen = std::max((int)final_ - (int)first, 0);
|
||||
|
||||
Value constructor = obj->speciesConstructor(state, state.context()->globalObject()->arrayBuffer());
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
Value arguments[] = { Value(newLen) };
|
||||
Object* newValue = Object::construct(state, constructor, 1, arguments).toObject(state);
|
||||
Value res = Object::construct(state, constructor, 1, arguments);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
Object* newValue = res.toObject(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (!newValue->isArrayBuffer()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().ArrayBuffer.string(), true, state.context()->staticStrings().slice.string(), "%s: return value of constructor ArrayBuffer is not valid ArrayBuffer");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().ArrayBuffer.string(), true, state.context()->staticStrings().slice.string(), "%s: return value of constructor ArrayBuffer is not valid ArrayBuffer");
|
||||
}
|
||||
|
||||
ArrayBuffer* newObject = newValue->asArrayBuffer();
|
||||
newObject->throwTypeErrorIfDetached(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
if (newObject == obj) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().ArrayBuffer.string(), true, state.context()->staticStrings().slice.string(), "%s: return value of constructor ArrayBuffer is not valid ArrayBuffer");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().ArrayBuffer.string(), true, state.context()->staticStrings().slice.string(), "%s: return value of constructor ArrayBuffer is not valid ArrayBuffer");
|
||||
}
|
||||
|
||||
if (newObject->byteLength() < newLen) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().ArrayBuffer.string(), true, state.context()->staticStrings().slice.string(), "%s: return value of constructor ArrayBuffer is not valid ArrayBuffer");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().ArrayBuffer.string(), true, state.context()->staticStrings().slice.string(), "%s: return value of constructor ArrayBuffer is not valid ArrayBuffer");
|
||||
}
|
||||
obj->throwTypeErrorIfDetached(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
newObject->fillData(obj->data() + first, newLen);
|
||||
return newObject;
|
||||
|
|
|
|||
|
|
@ -59,34 +59,33 @@ static Value asyncFromSyncIteratorValueUnwrap(ExecutionState& state, Value thisV
|
|||
static Value asyncFromSyncIteratorContinuation(ExecutionState& state, Object* result, PromiseReaction::Capability promiseCapability)
|
||||
{
|
||||
// Let done be IteratorComplete(result).
|
||||
bool done;
|
||||
try {
|
||||
done = IteratorObject::iteratorComplete(state, result);
|
||||
} catch (const Value& thrownValue) {
|
||||
bool done = IteratorObject::iteratorComplete(state, result);
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
// IfAbruptRejectPromise(done, promiseCapability).
|
||||
Value argv = thrownValue;
|
||||
Value argv = state.detachPendingException();
|
||||
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &argv);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
return promiseCapability.m_promise;
|
||||
}
|
||||
|
||||
// Let value be IteratorValue(result).
|
||||
Value value;
|
||||
try {
|
||||
value = IteratorObject::iteratorValue(state, result);
|
||||
} catch (const Value& thrownValue) {
|
||||
Value value = IteratorObject::iteratorValue(state, result);
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
// IfAbruptRejectPromise(value, promiseCapability).
|
||||
Value argv = thrownValue;
|
||||
Value argv = state.detachPendingException();
|
||||
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &argv);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
return promiseCapability.m_promise;
|
||||
}
|
||||
|
||||
// Let valueWrapper be ? PromiseResolve(%Promise%, « value »).
|
||||
PromiseObject* valueWrapper = nullptr;
|
||||
try {
|
||||
valueWrapper = PromiseObject::promiseResolve(state, state.context()->globalObject()->promise(), value)->asPromiseObject();
|
||||
} catch (const Value& thrownValue) {
|
||||
PromiseObject* valueWrapper = PromiseObject::promiseResolve(state, state.context()->globalObject()->promise(), value)->asPromiseObject();
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
// * added step from 2020 (esid: language/statements/for-await-of/async-from-sync-iterator-continuation-abrupt-completion-get-constructor.js)
|
||||
// IfAbruptRejectPromise(valueWrapper, promiseCapability).
|
||||
Value argv = thrownValue;
|
||||
Value argv = state.detachPendingException();
|
||||
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &argv);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
return promiseCapability.m_promise;
|
||||
}
|
||||
|
||||
|
|
@ -107,31 +106,36 @@ static Value builtinAsyncFromSyncIteratorNext(ExecutionState& state, Value thisV
|
|||
Value& O = thisValue;
|
||||
// Let promiseCapability be ! NewPromiseCapability(%Promise%).
|
||||
auto promiseCapability = PromiseObject::newPromiseCapability(state, state.context()->globalObject()->promise());
|
||||
ASSERT(!state.hasPendingException());
|
||||
// If Type(O) is not Object, or if O does not have a [[SyncIteratorRecord]] internal slot, then
|
||||
if (!O.isObject() || !O.asObject()->isAsyncFromSyncIteratorObject()) {
|
||||
// Let invalidIteratorError be a newly created TypeError object.
|
||||
Value invalidIteratorError = ErrorObject::createError(state, ErrorCode::TypeError, String::fromASCII("given this value is not Async-from-Sync Iterator"));
|
||||
// Perform ! Call(promiseCapability.[[Reject]], undefined, « invalidIteratorError »).
|
||||
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &invalidIteratorError);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Return promiseCapability.[[Promise]].
|
||||
return promiseCapability.m_promise;
|
||||
}
|
||||
// Let syncIteratorRecord be O.[[SyncIteratorRecord]].
|
||||
auto syncIteratorRecord = O.asObject()->asAsyncFromSyncIteratorObject()->syncIteratorRecord();
|
||||
Object* result;
|
||||
try {
|
||||
// Let result be IteratorNext(syncIteratorRecord, value).
|
||||
// If value is present, then
|
||||
// a. Let result be IteratorNext(syncIteratorRecord, value).
|
||||
// Else,
|
||||
// a. Let result be IteratorNext(syncIteratorRecord).
|
||||
result = IteratorObject::iteratorNext(state, syncIteratorRecord, argc ? argv[0] : Value(Value::EmptyValue));
|
||||
} catch (const Value& thrownValue) {
|
||||
|
||||
// Let result be IteratorNext(syncIteratorRecord, value).
|
||||
// If value is present, then
|
||||
// a. Let result be IteratorNext(syncIteratorRecord, value).
|
||||
// Else,
|
||||
// a. Let result be IteratorNext(syncIteratorRecord).
|
||||
result = IteratorObject::iteratorNext(state, syncIteratorRecord, argc ? argv[0] : Value(Value::EmptyValue));
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
// IfAbruptRejectPromise(result, promiseCapability).
|
||||
Value argv = thrownValue;
|
||||
Value argv = state.detachPendingException();
|
||||
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &argv);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
return promiseCapability.m_promise;
|
||||
}
|
||||
|
||||
// Return ! AsyncFromSyncIteratorContinuation(result, promiseCapability).
|
||||
return asyncFromSyncIteratorContinuation(state, result, promiseCapability);
|
||||
}
|
||||
|
|
@ -144,25 +148,26 @@ static Value builtinAsyncFromSyncIteratorReturn(ExecutionState& state, Value thi
|
|||
Value& O = thisValue;
|
||||
// Let promiseCapability be ! NewPromiseCapability(%Promise%).
|
||||
auto promiseCapability = PromiseObject::newPromiseCapability(state, state.context()->globalObject()->promise());
|
||||
ASSERT(!state.hasPendingException());
|
||||
// If Type(O) is not Object, or if O does not have a [[SyncIteratorRecord]] internal slot, then
|
||||
if (!O.isObject() || !O.asObject()->isAsyncFromSyncIteratorObject()) {
|
||||
// Let invalidIteratorError be a newly created TypeError object.
|
||||
Value invalidIteratorError = ErrorObject::createError(state, ErrorCode::TypeError, String::fromASCII("given this value is not Async-from-Sync Iterator"));
|
||||
// Perform ! Call(promiseCapability.[[Reject]], undefined, « invalidIteratorError »).
|
||||
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &invalidIteratorError);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Return promiseCapability.[[Promise]].
|
||||
return promiseCapability.m_promise;
|
||||
}
|
||||
// Let syncIterator be O.[[SyncIteratorRecord]].[[Iterator]].
|
||||
Object* syncIterator = O.asObject()->asAsyncFromSyncIteratorObject()->syncIteratorRecord()->m_iterator;
|
||||
// Let return be GetMethod(syncIterator, "return").
|
||||
Value returnVariable;
|
||||
try {
|
||||
returnVariable = Object::getMethod(state, syncIterator, state.context()->staticStrings().stringReturn);
|
||||
} catch (const Value& thrownValue) {
|
||||
Value returnVariable = Object::getMethod(state, syncIterator, state.context()->staticStrings().stringReturn);
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
// IfAbruptRejectPromise(return, promiseCapability).
|
||||
Value argv = thrownValue;
|
||||
Value argv = state.detachPendingException();
|
||||
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &argv);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
return promiseCapability.m_promise;
|
||||
}
|
||||
|
||||
|
|
@ -172,25 +177,26 @@ static Value builtinAsyncFromSyncIteratorReturn(ExecutionState& state, Value thi
|
|||
Value iterResult = IteratorObject::createIterResultObject(state, value, true);
|
||||
// Perform ! Call(promiseCapability.[[Resolve]], undefined, « iterResult »).
|
||||
Object::call(state, promiseCapability.m_resolveFunction, Value(), 1, &iterResult);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Return promiseCapability.[[Promise]].
|
||||
return promiseCapability.m_promise;
|
||||
}
|
||||
|
||||
Value result;
|
||||
try {
|
||||
// If value is present, then
|
||||
// a. Let result be Call(return, syncIterator, « value »).
|
||||
// Else,
|
||||
// a. Let result be Call(return, syncIterator).
|
||||
if (argc) {
|
||||
result = Object::call(state, returnVariable, syncIterator, 1, &value);
|
||||
} else {
|
||||
result = Object::call(state, returnVariable, syncIterator, 0, nullptr);
|
||||
}
|
||||
} catch (const Value& thrownValue) {
|
||||
// If value is present, then
|
||||
// a. Let result be Call(return, syncIterator, « value »).
|
||||
// Else,
|
||||
// a. Let result be Call(return, syncIterator).
|
||||
if (argc) {
|
||||
result = Object::call(state, returnVariable, syncIterator, 1, &value);
|
||||
} else {
|
||||
result = Object::call(state, returnVariable, syncIterator, 0, nullptr);
|
||||
}
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
// IfAbruptRejectPromise(return, promiseCapability).
|
||||
Value argv = thrownValue;
|
||||
Value argv = state.detachPendingException();
|
||||
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &argv);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
return promiseCapability.m_promise;
|
||||
}
|
||||
|
||||
|
|
@ -199,6 +205,7 @@ static Value builtinAsyncFromSyncIteratorReturn(ExecutionState& state, Value thi
|
|||
// Perform ! Call(promiseCapability.[[Reject]], undefined, « a newly created TypeError object »).
|
||||
Value typeError = ErrorObject::createError(state, ErrorCode::TypeError, String::fromASCII("result of iterator is not Object"));
|
||||
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &typeError);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Return promiseCapability.[[Promise]].
|
||||
return promiseCapability.m_promise;
|
||||
}
|
||||
|
|
@ -214,12 +221,14 @@ static Value builtinAsyncFromSyncIteratorThrow(ExecutionState& state, Value this
|
|||
Value& O = thisValue;
|
||||
// Let promiseCapability be ! NewPromiseCapability(%Promise%).
|
||||
auto promiseCapability = PromiseObject::newPromiseCapability(state, state.context()->globalObject()->promise());
|
||||
ASSERT(!state.hasPendingException());
|
||||
// If Type(O) is not Object, or if O does not have a [[SyncIteratorRecord]] internal slot, then
|
||||
if (!O.isObject() || !O.asObject()->isAsyncFromSyncIteratorObject()) {
|
||||
// Let invalidIteratorError be a newly created TypeError object.
|
||||
Value invalidIteratorError = ErrorObject::createError(state, ErrorCode::TypeError, String::fromASCII("given this value is not Async-from-Sync Iterator"));
|
||||
// Perform ! Call(promiseCapability.[[Reject]], undefined, « invalidIteratorError »).
|
||||
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &invalidIteratorError);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Return promiseCapability.[[Promise]].
|
||||
return promiseCapability.m_promise;
|
||||
}
|
||||
|
|
@ -227,13 +236,12 @@ static Value builtinAsyncFromSyncIteratorThrow(ExecutionState& state, Value this
|
|||
// Let syncIterator be O.[[SyncIteratorRecord]].[[Iterator]].
|
||||
Object* syncIterator = O.asObject()->asAsyncFromSyncIteratorObject()->syncIteratorRecord()->m_iterator;
|
||||
// Let throw be GetMethod(syncIterator, "throw").
|
||||
Value throwVariable;
|
||||
try {
|
||||
throwVariable = Object::getMethod(state, syncIterator, state.context()->staticStrings().stringThrow);
|
||||
} catch (const Value& thrownValue) {
|
||||
Value throwVariable = Object::getMethod(state, syncIterator, state.context()->staticStrings().stringThrow);
|
||||
if (state.hasPendingException()) {
|
||||
// IfAbruptRejectPromise(return, promiseCapability).
|
||||
Value argv = thrownValue;
|
||||
Value argv = state.detachPendingException();
|
||||
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &argv);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
return promiseCapability.m_promise;
|
||||
}
|
||||
|
||||
|
|
@ -241,18 +249,18 @@ static Value builtinAsyncFromSyncIteratorThrow(ExecutionState& state, Value this
|
|||
if (throwVariable.isUndefined()) {
|
||||
// Perform ! Call(promiseCapability.[[Reject]], undefined, « value »).
|
||||
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &value);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Return promiseCapability.[[Promise]].
|
||||
return promiseCapability.m_promise;
|
||||
}
|
||||
|
||||
// Let result be Call(throw, syncIterator, « value »).
|
||||
Value result;
|
||||
try {
|
||||
result = Object::call(state, throwVariable, syncIterator, 1, &value);
|
||||
} catch (const Value& thrownValue) {
|
||||
Value result = Object::call(state, throwVariable, syncIterator, 1, &value);
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
// IfAbruptRejectPromise(result, promiseCapability).
|
||||
Value argv = thrownValue;
|
||||
Value argv = state.detachPendingException();
|
||||
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &argv);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
return promiseCapability.m_promise;
|
||||
}
|
||||
|
||||
|
|
@ -261,6 +269,7 @@ static Value builtinAsyncFromSyncIteratorThrow(ExecutionState& state, Value this
|
|||
// Perform ! Call(promiseCapability.[[Reject]], undefined, « a newly created TypeError object »).
|
||||
Value typeError = ErrorObject::createError(state, ErrorCode::TypeError, String::fromASCII("result of iterator is not Object"));
|
||||
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &typeError);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Return promiseCapability.[[Promise]].
|
||||
return promiseCapability.m_promise;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ static Value builtinAsyncFunction(ExecutionState& state, Value thisValue, size_t
|
|||
size_t argumentVectorCount = argc > 1 ? argc - 1 : 0;
|
||||
Value sourceValue = argc >= 1 ? argv[argc - 1] : Value(String::emptyString);
|
||||
auto functionSource = FunctionObject::createDynamicFunctionScript(state, state.context()->staticStrings().anonymous, argumentVectorCount, argv, sourceValue, false, false, true, false);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// Let proto be ? GetPrototypeFromConstructor(newTarget, fallbackProto).
|
||||
if (!newTarget.hasValue()) {
|
||||
|
|
@ -40,6 +41,7 @@ static Value builtinAsyncFunction(ExecutionState& state, Value thisValue, size_t
|
|||
Object* proto = Object::getPrototypeFromConstructor(state, newTarget.value(), [](ExecutionState& state, Context* constructorRealm) -> Object* {
|
||||
return constructorRealm->globalObject()->asyncFunctionPrototype();
|
||||
});
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
return new ScriptAsyncFunctionObject(state, proto, functionSource.codeBlock, functionSource.outerEnvironment);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ static Value builtinAsyncGeneratorFunction(ExecutionState& state, Value thisValu
|
|||
size_t argumentVectorCount = argc > 1 ? argc - 1 : 0;
|
||||
Value sourceValue = argc >= 1 ? argv[argc - 1] : Value(String::emptyString);
|
||||
auto functionSource = FunctionObject::createDynamicFunctionScript(state, state.context()->staticStrings().anonymous, argumentVectorCount, argv, sourceValue, false, true, true, false);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// Let proto be ? GetPrototypeFromConstructor(newTarget, fallbackProto).
|
||||
if (!newTarget.hasValue()) {
|
||||
|
|
@ -40,6 +41,7 @@ static Value builtinAsyncGeneratorFunction(ExecutionState& state, Value thisValu
|
|||
Object* proto = Object::getPrototypeFromConstructor(state, newTarget.value(), [](ExecutionState& state, Context* constructorRealm) -> Object* {
|
||||
return constructorRealm->globalObject()->asyncGenerator();
|
||||
});
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
return new ScriptAsyncGeneratorFunctionObject(state, proto, functionSource.codeBlock, functionSource.outerEnvironment);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,14 +48,15 @@ enum class AtomicBinaryOps : uint8_t {
|
|||
static ArrayBuffer* validateIntegerTypedArray(ExecutionState& state, Value typedArray, bool waitable = false)
|
||||
{
|
||||
ArrayBuffer* buffer = TypedArrayObject::validateTypedArray(state, typedArray);
|
||||
RETURN_NULL_IF_PENDING_EXCEPTION
|
||||
TypedArrayObject* TA = typedArray.asObject()->asTypedArrayObject();
|
||||
|
||||
if (waitable) {
|
||||
if ((TA->typedArrayType() != TypedArrayType::Int32) && (TA->typedArrayType() != TypedArrayType::BigInt64)) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_IllegalFirstArgument);
|
||||
THROW_BUILTIN_ERROR_RETURN_NULL(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_IllegalFirstArgument);
|
||||
}
|
||||
} else if ((TA->typedArrayType() == TypedArrayType::Uint8Clamped) || (TA->typedArrayType() == TypedArrayType::Float32) || (TA->typedArrayType() == TypedArrayType::Float64)) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_IllegalFirstArgument);
|
||||
THROW_BUILTIN_ERROR_RETURN_NULL(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_IllegalFirstArgument);
|
||||
}
|
||||
|
||||
return buffer;
|
||||
|
|
@ -66,7 +67,7 @@ static size_t validateAtomicAccess(ExecutionState& state, TypedArrayObject* type
|
|||
uint64_t accessIndex = index.toIndex(state);
|
||||
size_t length = typedArray->arrayLength();
|
||||
if (UNLIKELY(accessIndex == Value::InvalidIndexValue || accessIndex >= (uint64_t)length)) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, ErrorObject::Messages::GlobalObject_RangeError);
|
||||
THROW_BUILTIN_ERROR_RETURN_ZERO(state, ErrorCode::RangeError, ErrorObject::Messages::GlobalObject_RangeError);
|
||||
}
|
||||
|
||||
ASSERT(accessIndex < std::numeric_limits<size_t>::max());
|
||||
|
|
@ -166,6 +167,7 @@ static Value getModifySetValueInBuffer(ExecutionState& state, ArrayBuffer* buffe
|
|||
static Value atomicReadModifyWrite(ExecutionState& state, Value typedArray, Value index, Value value, AtomicBinaryOps op)
|
||||
{
|
||||
ArrayBuffer* buffer = validateIntegerTypedArray(state, typedArray);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
TypedArrayObject* TA = typedArray.asObject()->asTypedArrayObject();
|
||||
size_t indexedPosition = validateAtomicAccess(state, TA, index);
|
||||
TypedArrayType type = TA->typedArrayType();
|
||||
|
|
@ -173,6 +175,7 @@ static Value atomicReadModifyWrite(ExecutionState& state, Value typedArray, Valu
|
|||
Value v;
|
||||
if (type == TypedArrayType::BigInt64 || type == TypedArrayType::BigUint64) {
|
||||
v = value.toBigInt(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
} else {
|
||||
v = Value(Value::DoubleToIntConvertibleTestNeeds, value.toInteger(state));
|
||||
}
|
||||
|
|
@ -202,15 +205,19 @@ void atomicCompareExchange(uint8_t* rawStart, uint8_t* expectedBytes, uint8_t* r
|
|||
static Value builtinAtomicsCompareExchange(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
ArrayBuffer* buffer = validateIntegerTypedArray(state, argv[0]);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
TypedArrayObject* TA = argv[0].asObject()->asTypedArrayObject();
|
||||
size_t indexedPosition = validateAtomicAccess(state, TA, argv[1]);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
TypedArrayType type = TA->typedArrayType();
|
||||
|
||||
Value expected;
|
||||
Value replacement;
|
||||
if (type == TypedArrayType::BigInt64 || type == TypedArrayType::BigUint64) {
|
||||
expected = argv[2].toBigInt(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
replacement = argv[3].toBigInt(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
} else {
|
||||
expected = Value(Value::DoubleToIntConvertibleTestNeeds, argv[2].toInteger(state));
|
||||
replacement = Value(Value::DoubleToIntConvertibleTestNeeds, argv[3].toInteger(state));
|
||||
|
|
@ -283,8 +290,10 @@ static Value builtinAtomicsExchange(ExecutionState& state, Value thisValue, size
|
|||
static Value builtinAtomicsLoad(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
ArrayBuffer* buffer = validateIntegerTypedArray(state, argv[0]);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
TypedArrayObject* TA = argv[0].asObject()->asTypedArrayObject();
|
||||
size_t indexedPosition = validateAtomicAccess(state, TA, argv[1]);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
TypedArrayType type = TA->typedArrayType();
|
||||
|
||||
return buffer->getValueFromBuffer(state, indexedPosition, type);
|
||||
|
|
@ -298,14 +307,17 @@ static Value builtinAtomicsOr(ExecutionState& state, Value thisValue, size_t arg
|
|||
static Value builtinAtomicsStore(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
ArrayBuffer* buffer = validateIntegerTypedArray(state, argv[0]);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
TypedArrayObject* TA = argv[0].asObject()->asTypedArrayObject();
|
||||
size_t indexedPosition = validateAtomicAccess(state, TA, argv[1]);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
TypedArrayType type = TA->typedArrayType();
|
||||
|
||||
Value value = argv[2];
|
||||
Value v;
|
||||
if (type == TypedArrayType::BigInt64 || type == TypedArrayType::BigUint64) {
|
||||
v = value.toBigInt(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
} else {
|
||||
v = Value(Value::DoubleToIntConvertibleTestNeeds, value.toInteger(state));
|
||||
}
|
||||
|
|
@ -329,19 +341,22 @@ static Value doWait(ExecutionState& state, bool isAsync, const Value& typedArray
|
|||
// https://tc39.es/proposal-atomics-wait-async/#sec-dowait
|
||||
// Let buffer be ? ValidateSharedIntegerTypedArray(typedArray, true).
|
||||
ArrayBuffer* buffer = validateIntegerTypedArray(state, typedArrayValue, true);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
TypedArrayObject* typedArray = typedArrayValue.asObject()->asTypedArrayObject();
|
||||
if (!buffer->isSharedArrayBufferObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "This function expects SharedArrayBuffer");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "This function expects SharedArrayBuffer");
|
||||
}
|
||||
|
||||
// Let i be ? ValidateAtomicAccess(typedArray, index).
|
||||
size_t i = validateAtomicAccess(state, typedArray, index);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Let arrayTypeName be typedArray.[[TypedArrayName]].
|
||||
auto arrayTypeName = typedArray->typedArrayType();
|
||||
// If arrayTypeName is "BigInt64Array", let v be ? ToBigInt64(value).
|
||||
Value v;
|
||||
if (arrayTypeName == TypedArrayType::BigInt64) {
|
||||
v = value.toBigInt(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
} else {
|
||||
// Otherwise, let v be ? ToInt32(value).
|
||||
v = Value(value.toInt32(state));
|
||||
|
|
@ -363,7 +378,7 @@ static Value doWait(ExecutionState& state, bool isAsync, const Value& typedArray
|
|||
// Let B be AgentCanSuspend().
|
||||
// If B is false, throw a TypeError exception.
|
||||
if (!Global::platform()->canBlockExecution(state.context())) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Cannot suspend this thread");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Cannot suspend this thread");
|
||||
}
|
||||
}
|
||||
// Let block be buffer.[[ArrayBufferData]].
|
||||
|
|
@ -381,6 +396,7 @@ static Value doWait(ExecutionState& state, bool isAsync, const Value& typedArray
|
|||
if (isAsync) {
|
||||
// Set promiseCapability to ! NewPromiseCapability(%Promise%).
|
||||
promiseCapability = PromiseObject::newPromiseCapability(state, state.context()->globalObject()->promise());
|
||||
ASSERT(!state.hasPendingException());
|
||||
// Set resultObject to ! OrdinaryObjectCreate(%Object.prototype%).
|
||||
resultObject = new Object(state);
|
||||
}
|
||||
|
|
@ -404,6 +420,7 @@ static Value doWait(ExecutionState& state, bool isAsync, const Value& typedArray
|
|||
resultObject->defineOwnPropertyThrowsException(state, ObjectPropertyName(state.context()->staticStrings().async), ObjectPropertyDescriptor(Value(false), ObjectPropertyDescriptor::PresentAttribute::AllPresent));
|
||||
// Perform ! CreateDataPropertyOrThrow(resultObject, "value", "not-equal").
|
||||
resultObject->defineOwnPropertyThrowsException(state, ObjectPropertyName(state.context()->staticStrings().value), ObjectPropertyDescriptor(state.context()->staticStrings().lazyNotEqual().string(), ObjectPropertyDescriptor::PresentAttribute::AllPresent));
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Return resultObject.
|
||||
return Value(resultObject.value());
|
||||
}
|
||||
|
|
@ -416,6 +433,7 @@ static Value doWait(ExecutionState& state, bool isAsync, const Value& typedArray
|
|||
resultObject->defineOwnPropertyThrowsException(state, ObjectPropertyName(state.context()->staticStrings().async), ObjectPropertyDescriptor(Value(false), ObjectPropertyDescriptor::PresentAttribute::AllPresent));
|
||||
// Perform ! CreateDataPropertyOrThrow(resultObject, "value", "timed-out").
|
||||
resultObject->defineOwnPropertyThrowsException(state, ObjectPropertyName(state.context()->staticStrings().value), ObjectPropertyDescriptor(state.context()->staticStrings().lazyTimedOut().string(), ObjectPropertyDescriptor::PresentAttribute::AllPresent));
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Return resultObject.
|
||||
return Value(resultObject.value());
|
||||
}
|
||||
|
|
@ -476,6 +494,7 @@ static Value doWait(ExecutionState& state, bool isAsync, const Value& typedArray
|
|||
|
||||
resultObject->defineOwnPropertyThrowsException(state, ObjectPropertyName(state.context()->staticStrings().async), ObjectPropertyDescriptor(Value(true), ObjectPropertyDescriptor::PresentAttribute::AllPresent));
|
||||
resultObject->defineOwnPropertyThrowsException(state, ObjectPropertyName(state.context()->staticStrings().value), ObjectPropertyDescriptor(promiseCapability.m_promise, ObjectPropertyDescriptor::PresentAttribute::AllPresent));
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
return Value(resultObject.value());
|
||||
} else {
|
||||
bool notified = true;
|
||||
|
|
@ -512,9 +531,11 @@ static Value builtinAtomicsNotify(ExecutionState& state, Value thisValue, size_t
|
|||
// Atomics.notify ( typedArray, index, count )
|
||||
// 1. Let buffer be ? ValidateIntegerTypedArray(typedArray, true).
|
||||
ArrayBuffer* buffer = validateIntegerTypedArray(state, argv[0], true);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
TypedArrayObject* typedArray = argv[0].asObject()->asTypedArrayObject();
|
||||
// 2. Let indexedPosition be ? ValidateAtomicAccess(typedArray, index).
|
||||
size_t indexedPosition = validateAtomicAccess(state, typedArray, argv[1]);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
double c;
|
||||
// 3. If count is undefined, let c be +∞.
|
||||
if (argv[2].isUndefined()) {
|
||||
|
|
|
|||
|
|
@ -35,16 +35,17 @@ static Value builtinBigIntConstructor(ExecutionState& state, Value thisValue, si
|
|||
{
|
||||
// If NewTarget is not undefined, throw a TypeError exception.
|
||||
if (newTarget.hasValue()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "illegal constructor BigInt");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "illegal constructor BigInt");
|
||||
}
|
||||
// Let prim be ? ToPrimitive(value, hint Number).
|
||||
Value prim = argv[0].toPrimitive(state, Value::PreferNumber);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// If Type(prim) is Number, return ? NumberToBigInt(prim).
|
||||
if (prim.isNumber()) {
|
||||
// NumberToBigInt(prim)
|
||||
// If IsInteger(number) is false, throw a RangeError exception.
|
||||
if (!prim.isInteger(state)) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, "The value you input to BigInt constructor is not integer");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::RangeError, "The value you input to BigInt constructor is not integer");
|
||||
}
|
||||
double numValue = prim.asNumber();
|
||||
if ((numValue > (double)std::numeric_limits<int64_t>::max()) || (numValue < (double)std::numeric_limits<int64_t>::min())) {
|
||||
|
|
@ -61,7 +62,9 @@ static Value builtinBigIntConstructor(ExecutionState& state, Value thisValue, si
|
|||
return new BigInt((int64_t)numValue);
|
||||
} else {
|
||||
// Otherwise, return ? ToBigInt(value).
|
||||
return argv[0].toBigInt(state);
|
||||
BigInt* result = argv[0].toBigInt(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -69,11 +72,13 @@ static Value builtinBigIntAsUintN(ExecutionState& state, Value thisValue, size_t
|
|||
{
|
||||
// Let bits be ? ToIndex(bits).
|
||||
auto bits = argv[0].toIndex(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (bits == Value::InvalidIndexValue) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, ErrorObject::Messages::CanNotConvertValueToIndex);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::RangeError, ErrorObject::Messages::CanNotConvertValueToIndex);
|
||||
}
|
||||
// Let bigint be ? ToBigInt(bigint).
|
||||
BigInt* bigint = argv[1].toBigInt(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Return a BigInt representing bigint modulo 2bits.
|
||||
bf_t mask, r;
|
||||
bf_init(ThreadLocal::bfContext(), &mask);
|
||||
|
|
@ -91,11 +96,13 @@ static Value builtinBigIntAsIntN(ExecutionState& state, Value thisValue, size_t
|
|||
{
|
||||
// Let bits be ? ToIndex(bits).
|
||||
auto bits = argv[0].toIndex(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (bits == Value::InvalidIndexValue) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, ErrorObject::Messages::CanNotConvertValueToIndex);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::RangeError, ErrorObject::Messages::CanNotConvertValueToIndex);
|
||||
}
|
||||
// Let bigint be ? ToBigInt(bigint).
|
||||
BigInt* bigint = argv[1].toBigInt(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Return a BigInt representing bigint modulo 2bits.
|
||||
bf_t mask, r;
|
||||
bf_init(ThreadLocal::bfContext(), &mask);
|
||||
|
|
@ -124,18 +131,18 @@ static Value builtinBigIntAsIntN(ExecutionState& state, Value thisValue, size_t
|
|||
// Assert: Type(value.[[BigIntData]]) is BigInt.
|
||||
// Return value.[[BigIntData]].
|
||||
// Throw a TypeError exception.
|
||||
#define RESOLVE_THIS_BINDING_TO_BIGINT(NAME, OBJ, BUILT_IN_METHOD) \
|
||||
BigInt* NAME = nullptr; \
|
||||
if (thisValue.isObject()) { \
|
||||
if (!thisValue.asObject()->isBigIntObject()) { \
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().OBJ.string(), true, state.context()->staticStrings().BUILT_IN_METHOD.string(), ErrorObject::Messages::GlobalObject_CalledOnIncompatibleReceiver); \
|
||||
} \
|
||||
NAME = thisValue.asObject()->asBigIntObject()->primitiveValue(); \
|
||||
} else if (thisValue.isBigInt()) { \
|
||||
NAME = thisValue.asBigInt(); \
|
||||
} else { \
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().OBJ.string(), true, state.context()->staticStrings().BUILT_IN_METHOD.string(), ErrorObject::Messages::GlobalObject_CalledOnIncompatibleReceiver); \
|
||||
return Value(); \
|
||||
#define RESOLVE_THIS_BINDING_TO_BIGINT(NAME, OBJ, BUILT_IN_METHOD) \
|
||||
BigInt* NAME = nullptr; \
|
||||
if (thisValue.isObject()) { \
|
||||
if (!thisValue.asObject()->isBigIntObject()) { \
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().OBJ.string(), true, state.context()->staticStrings().BUILT_IN_METHOD.string(), ErrorObject::Messages::GlobalObject_CalledOnIncompatibleReceiver); \
|
||||
} \
|
||||
NAME = thisValue.asObject()->asBigIntObject()->primitiveValue(); \
|
||||
} else if (thisValue.isBigInt()) { \
|
||||
NAME = thisValue.asBigInt(); \
|
||||
} else { \
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().OBJ.string(), true, state.context()->staticStrings().BUILT_IN_METHOD.string(), ErrorObject::Messages::GlobalObject_CalledOnIncompatibleReceiver); \
|
||||
return Value(); \
|
||||
}
|
||||
|
||||
static Value builtinBigIntToString(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
|
|
@ -146,7 +153,7 @@ static Value builtinBigIntToString(ExecutionState& state, Value thisValue, size_
|
|||
if (argc > 0 && !argv[0].isUndefined()) {
|
||||
radix = argv[0].toInteger(state);
|
||||
if (radix < 2 || radix > 36) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, state.context()->staticStrings().Number.string(), true, state.context()->staticStrings().toString.string(), ErrorObject::Messages::GlobalObject_RadixInvalidRange);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::RangeError, state.context()->staticStrings().Number.string(), true, state.context()->staticStrings().toString.string(), ErrorObject::Messages::GlobalObject_RadixInvalidRange);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -175,12 +182,15 @@ static Value builtinBigIntToLocaleString(ExecutionState& state, Value thisValue,
|
|||
ObjectGetResult toStrFuncGetResult = state.context()->globalObject()->bigIntProxyObject()->get(state, ObjectPropertyName(state.context()->staticStrings().toString));
|
||||
if (toStrFuncGetResult.hasValue()) {
|
||||
Value toStrFunc = toStrFuncGetResult.value(state, thisObject);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (toStrFunc.isCallable()) {
|
||||
// toLocaleString() ignores the first argument, unlike toString()
|
||||
return Object::call(state, toStrFunc, thisObject, 0, argv);
|
||||
Value result = Object::call(state, toStrFunc, thisObject, 0, argv);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
return result;
|
||||
}
|
||||
}
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().BigInt.string(), true, state.context()->staticStrings().toLocaleString.string(), ErrorObject::Messages::GlobalObject_ToLocaleStringNotCallable);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().BigInt.string(), true, state.context()->staticStrings().toLocaleString.string(), ErrorObject::Messages::GlobalObject_ToLocaleStringNotCallable);
|
||||
RELEASE_ASSERT_NOT_REACHED();
|
||||
return Value();
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ static Value builtinBooleanConstructor(ExecutionState& state, Value thisValue, s
|
|||
Object* proto = Object::getPrototypeFromConstructor(state, newTarget.value(), [](ExecutionState& state, Context* constructorRealm) -> Object* {
|
||||
return constructorRealm->globalObject()->booleanPrototype();
|
||||
});
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
BooleanObject* boolObj = new BooleanObject(state, proto, primitiveVal);
|
||||
return boolObj;
|
||||
}
|
||||
|
|
@ -46,7 +47,7 @@ static Value builtinBooleanValueOf(ExecutionState& state, Value thisValue, size_
|
|||
} else if (thisValue.isObject() && thisValue.asObject()->isBooleanObject()) {
|
||||
return Value(thisValue.asPointerValue()->asBooleanObject()->primitiveValue());
|
||||
}
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ThisNotBoolean);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ThisNotBoolean);
|
||||
RELEASE_ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
|
|
@ -57,7 +58,7 @@ static Value builtinBooleanToString(ExecutionState& state, Value thisValue, size
|
|||
} else if (thisValue.isObject() && thisValue.asObject()->isBooleanObject()) {
|
||||
return Value(thisValue.asPointerValue()->asBooleanObject()->primitiveValue()).toString(state);
|
||||
}
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ThisNotBoolean);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ThisNotBoolean);
|
||||
RELEASE_ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -41,11 +41,10 @@ namespace Escargot {
|
|||
static Value builtinDataViewConstructor(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (!newTarget.hasValue()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ConstructorRequiresNew);
|
||||
return Value();
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ConstructorRequiresNew);
|
||||
}
|
||||
if (!(argv[0].isObject() && argv[0].asPointerValue()->isArrayBuffer())) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().DataView.string(), false, String::emptyString, ErrorObject::Messages::GlobalObject_ThisNotArrayBufferObject);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().DataView.string(), false, String::emptyString, ErrorObject::Messages::GlobalObject_ThisNotArrayBufferObject);
|
||||
}
|
||||
|
||||
ArrayBuffer* buffer = argv[0].asObject()->asArrayBuffer();
|
||||
|
|
@ -53,17 +52,18 @@ static Value builtinDataViewConstructor(ExecutionState& state, Value thisValue,
|
|||
if (argc >= 2) {
|
||||
Value& val = argv[1];
|
||||
byteOffset = val.toIndex(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (byteOffset == Value::InvalidIndexValue) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, state.context()->staticStrings().DataView.string(), false, String::emptyString, ErrorObject::Messages::GlobalObject_InvalidArrayBufferOffset);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::RangeError, state.context()->staticStrings().DataView.string(), false, String::emptyString, ErrorObject::Messages::GlobalObject_InvalidArrayBufferOffset);
|
||||
}
|
||||
}
|
||||
if (buffer->isDetachedBuffer()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().DataView.string(), false, String::emptyString, "%s: ArrayBuffer is detached buffer");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().DataView.string(), false, String::emptyString, "%s: ArrayBuffer is detached buffer");
|
||||
}
|
||||
double bufferByteLength = buffer->byteLength();
|
||||
|
||||
if (byteOffset > bufferByteLength) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, state.context()->staticStrings().DataView.string(), false, String::emptyString, ErrorObject::Messages::GlobalObject_InvalidArrayBufferOffset);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::RangeError, state.context()->staticStrings().DataView.string(), false, String::emptyString, ErrorObject::Messages::GlobalObject_InvalidArrayBufferOffset);
|
||||
}
|
||||
double byteLength = bufferByteLength - byteOffset;
|
||||
|
||||
|
|
@ -71,8 +71,9 @@ static Value builtinDataViewConstructor(ExecutionState& state, Value thisValue,
|
|||
Value& val = argv[2];
|
||||
if (!val.isUndefined()) {
|
||||
byteLength = val.toIndex(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (byteOffset + byteLength > bufferByteLength || byteLength == Value::InvalidIndexValue) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, state.context()->staticStrings().DataView.string(), false, String::emptyString, ErrorObject::Messages::GlobalObject_InvalidArrayBufferOffset);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::RangeError, state.context()->staticStrings().DataView.string(), false, String::emptyString, ErrorObject::Messages::GlobalObject_InvalidArrayBufferOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -80,11 +81,12 @@ static Value builtinDataViewConstructor(ExecutionState& state, Value thisValue,
|
|||
Object* proto = Object::getPrototypeFromConstructor(state, newTarget.value(), [](ExecutionState& state, Context* constructorRealm) -> Object* {
|
||||
return constructorRealm->globalObject()->dataViewPrototype();
|
||||
});
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
ArrayBufferView* obj = new DataViewObject(state, proto);
|
||||
obj->setBuffer(buffer, byteOffset, byteLength);
|
||||
|
||||
if (obj->buffer()->isDetachedBuffer()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().DataView.string(), false, String::emptyString, ErrorObject::Messages::GlobalObject_DetachedBuffer);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().DataView.string(), false, String::emptyString, ErrorObject::Messages::GlobalObject_DetachedBuffer);
|
||||
}
|
||||
|
||||
return obj;
|
||||
|
|
@ -95,9 +97,9 @@ static Value builtinDataViewConstructor(ExecutionState& state, Value thisValue,
|
|||
{ \
|
||||
RESOLVE_THIS_BINDING_TO_OBJECT(thisObject, DataView, get##Name); \
|
||||
if (!(thisObject->isDataViewObject())) { \
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().DataView.string(), \
|
||||
true, state.context()->staticStrings().get##Name.string(), \
|
||||
ErrorObject::Messages::GlobalObject_ThisNotDataViewObject); \
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().DataView.string(), \
|
||||
true, state.context()->staticStrings().get##Name.string(), \
|
||||
ErrorObject::Messages::GlobalObject_ThisNotDataViewObject); \
|
||||
} \
|
||||
if (argc < 2) { \
|
||||
return thisObject->asDataViewObject()->getViewValue(state, argv[0], Value(false), TypedArrayType::Name); \
|
||||
|
|
@ -111,9 +113,9 @@ static Value builtinDataViewConstructor(ExecutionState& state, Value thisValue,
|
|||
{ \
|
||||
RESOLVE_THIS_BINDING_TO_OBJECT(thisObject, DataView, get##Name); \
|
||||
if (!(thisObject->isDataViewObject())) { \
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().DataView.string(), \
|
||||
true, state.context()->staticStrings().set##Name.string(), \
|
||||
ErrorObject::Messages::GlobalObject_ThisNotDataViewObject); \
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().DataView.string(), \
|
||||
true, state.context()->staticStrings().set##Name.string(), \
|
||||
ErrorObject::Messages::GlobalObject_ThisNotDataViewObject); \
|
||||
} \
|
||||
if (argc < 3) { \
|
||||
return thisObject->asDataViewObject()->setViewValue(state, argv[0], Value(false), TypedArrayType::Name, argv[1]); \
|
||||
|
|
@ -133,7 +135,7 @@ static Value builtinDataViewBufferGetter(ExecutionState& state, Value thisValue,
|
|||
return Value(buffer);
|
||||
}
|
||||
}
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "get DataView.prototype.buffer called on incompatible receiver");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "get DataView.prototype.buffer called on incompatible receiver");
|
||||
RELEASE_ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
|
|
@ -142,7 +144,7 @@ static Value builtinDataViewByteLengthGetter(ExecutionState& state, Value thisVa
|
|||
if (LIKELY(thisValue.isPointerValue() && thisValue.asPointerValue()->isDataViewObject() && thisValue.asObject()->asDataViewObject()->buffer() && !thisValue.asObject()->asDataViewObject()->buffer()->isDetachedBuffer())) {
|
||||
return Value(thisValue.asObject()->asArrayBufferView()->byteLength());
|
||||
}
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "get DataView.prototype.byteLength called on incompatible receiver");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "get DataView.prototype.byteLength called on incompatible receiver");
|
||||
RELEASE_ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
|
|
@ -151,7 +153,7 @@ static Value builtinDataViewByteOffsetGetter(ExecutionState& state, Value thisVa
|
|||
if (LIKELY(thisValue.isPointerValue() && thisValue.asPointerValue()->isDataViewObject() && thisValue.asObject()->asDataViewObject()->buffer() && !thisValue.asObject()->asDataViewObject()->buffer()->isDetachedBuffer())) {
|
||||
return Value(thisValue.asObject()->asArrayBufferView()->byteOffset());
|
||||
}
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "get DataView.prototype.byteOffset called on incompatible receiver");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "get DataView.prototype.byteOffset called on incompatible receiver");
|
||||
RELEASE_ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -77,6 +77,7 @@ static Value builtinDateConstructor(ExecutionState& state, Value thisValue, size
|
|||
Object* proto = Object::getPrototypeFromConstructor(state, newTarget.value(), [](ExecutionState& state, Context* constructorRealm) -> Object* {
|
||||
return constructorRealm->globalObject()->datePrototype();
|
||||
});
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
DateObject* thisObject = new DateObject(state, proto);
|
||||
|
||||
if (argc == 0) {
|
||||
|
|
@ -92,12 +93,15 @@ static Value builtinDateConstructor(ExecutionState& state, Value thisValue, size
|
|||
} else {
|
||||
// Let v be ToPrimitive(value).
|
||||
v = v.toPrimitive(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// If Type(v) is String, then
|
||||
if (v.isString()) {
|
||||
thisObject->setTimeValue(state, v);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
} else {
|
||||
// Let tv be ToNumber(v).
|
||||
double V = v.toNumber(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
thisObject->setTimeValue(DateObject::timeClip(state, V));
|
||||
}
|
||||
}
|
||||
|
|
@ -109,6 +113,7 @@ static Value builtinDateConstructor(ExecutionState& state, Value thisValue, size
|
|||
argc = (argc > 7) ? 7 : argc; // trim arguments so that they don't corrupt stack
|
||||
for (size_t i = 0; i < argc; i++) {
|
||||
args[i] = argv[i].toNumber(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
}
|
||||
double year = args[0];
|
||||
double month = args[1];
|
||||
|
|
@ -138,9 +143,11 @@ static Value builtinDateNow(ExecutionState& state, Value thisValue, size_t argc,
|
|||
static Value builtinDateParse(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
Value str = argv[0].toPrimitive(state, Value::PreferString);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (str.isString()) {
|
||||
DateObject d(state);
|
||||
d.setTimeValue(state, str);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
return Value(Value::DoubleToIntConvertibleTestNeeds, d.primitiveValue());
|
||||
}
|
||||
return Value(Value::NanInit);
|
||||
|
|
@ -153,6 +160,7 @@ static Value builtinDateUTC(ExecutionState& state, Value thisValue, size_t argc,
|
|||
argc = (argc > 7) ? 7 : argc; // trim arguments so that they don't corrupt stack
|
||||
for (size_t i = 0; i < argc; i++) {
|
||||
args[i] = argv[i].toNumber(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
}
|
||||
double year = args[0];
|
||||
double month = args[1];
|
||||
|
|
@ -178,10 +186,10 @@ static Value builtinDateUTC(ExecutionState& state, Value thisValue, size_t argc,
|
|||
return Value(Value::DoubleToIntConvertibleTestNeeds, d.primitiveValue());
|
||||
}
|
||||
|
||||
#define RESOLVE_THIS_BINDING_TO_DATE(NAME, OBJ, BUILT_IN_METHOD) \
|
||||
if (!thisValue.isObject() || !thisValue.asObject()->isDateObject()) { \
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().OBJ.string(), true, state.context()->staticStrings().BUILT_IN_METHOD.string(), ErrorObject::Messages::GlobalObject_ThisNotDateObject); \
|
||||
} \
|
||||
#define RESOLVE_THIS_BINDING_TO_DATE(NAME, OBJ, BUILT_IN_METHOD) \
|
||||
if (!thisValue.isObject() || !thisValue.asObject()->isDateObject()) { \
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().OBJ.string(), true, state.context()->staticStrings().BUILT_IN_METHOD.string(), ErrorObject::Messages::GlobalObject_ThisNotDateObject); \
|
||||
} \
|
||||
DateObject* NAME = thisValue.asObject()->asDateObject();
|
||||
|
||||
static Value builtinDateGetTime(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
|
|
@ -281,11 +289,13 @@ static Value builtinDateToJSON(ExecutionState& state, Value thisValue, size_t ar
|
|||
RESOLVE_THIS_BINDING_TO_OBJECT(thisObject, Date, toJSON);
|
||||
|
||||
Value tv = Value(thisObject).toPrimitive(state, Value::PreferNumber);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (tv.isNumber() && (std::isnan(tv.asNumber()) || std::isinf(tv.asNumber()))) {
|
||||
return Value(Value::Null);
|
||||
}
|
||||
|
||||
Value isoFunc = thisObject->get(state, ObjectPropertyName(state.context()->staticStrings().toISOString)).value(state, thisObject);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
return Object::call(state, isoFunc, thisObject, 0, nullptr);
|
||||
}
|
||||
|
||||
|
|
@ -375,6 +385,7 @@ static Value builtinDateSetHelper(ExecutionState& state, DateSetterType setterTy
|
|||
RELEASE_ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (UNLIKELY(!isInValidRange(year, month, date, hour, minute, second, millisecond))) {
|
||||
d->setTimeValueAsNaN();
|
||||
} else if (d->isValid()) {
|
||||
|
|
@ -396,7 +407,10 @@ static Value builtinDateSetTime(ExecutionState& state, Value thisValue, size_t a
|
|||
{
|
||||
RESOLVE_THIS_BINDING_TO_DATE(thisObject, Date, setTime);
|
||||
if (argc > 0) {
|
||||
thisObject->setTimeValue(DateObject::timeClip(state, argv[0].toNumber(state)));
|
||||
double num = argv[0].toNumber(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
thisObject->setTimeValue(DateObject::timeClip(state, num));
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
return Value(Value::DoubleToIntConvertibleTestNeeds, thisObject->primitiveValue());
|
||||
} else {
|
||||
thisObject->setTimeValueAsNaN();
|
||||
|
|
@ -435,6 +449,7 @@ static Value builtinDateSetYear(ExecutionState& state, Value thisValue, size_t a
|
|||
|
||||
// Let y be ToNumber(year).
|
||||
y = argv[0].toNumber(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// If y is NaN, set the [[DateValue]] internal slot of this Date object to NaN and return NaN.
|
||||
if (std::isnan(y)) {
|
||||
d->setTimeValueAsNaN();
|
||||
|
|
@ -479,8 +494,8 @@ static Value builtinDateToPrimitive(ExecutionState& state, Value thisValue, size
|
|||
Value O = thisValue;
|
||||
// If Type(O) is not Object, throw a TypeError exception.
|
||||
if (!O.isObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().Date.string(), true,
|
||||
state.context()->staticStrings().toPrimitive.string(), ErrorObject::Messages::GlobalObject_ThisNotObject);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Date.string(), true,
|
||||
state.context()->staticStrings().toPrimitive.string(), ErrorObject::Messages::GlobalObject_ThisNotObject);
|
||||
}
|
||||
bool tryFirstIsString = false;
|
||||
// If hint is the String value "string" or the String value "default", then
|
||||
|
|
@ -493,8 +508,8 @@ static Value builtinDateToPrimitive(ExecutionState& state, Value thisValue, size
|
|||
tryFirstIsString = false;
|
||||
} else {
|
||||
// Else, throw a TypeError exception.
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().Date.string(), true,
|
||||
state.context()->staticStrings().toPrimitive.string(), ErrorObject::Messages::GlobalObject_IllegalFirstArgument);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Date.string(), true,
|
||||
state.context()->staticStrings().toPrimitive.string(), ErrorObject::Messages::GlobalObject_IllegalFirstArgument);
|
||||
}
|
||||
// Return ? OrdinaryToPrimitive(O, tryFirst).
|
||||
if (tryFirstIsString) {
|
||||
|
|
|
|||
|
|
@ -52,16 +52,19 @@ static Value builtinErrorConstructor(ExecutionState& state, Value thisValue, siz
|
|||
Object* proto = Object::getPrototypeFromConstructor(state, newTarget.value(), [](ExecutionState& state, Context* constructorRealm) -> Object* {
|
||||
return constructorRealm->globalObject()->errorPrototype();
|
||||
});
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
ErrorObject* obj = new ErrorObject(state, proto, String::emptyString);
|
||||
|
||||
Value message = argv[0];
|
||||
if (!message.isUndefined()) {
|
||||
obj->defineOwnPropertyThrowsException(state, state.context()->staticStrings().message,
|
||||
ObjectPropertyDescriptor(message.toString(state), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectStructurePropertyDescriptor::ConfigurablePresent)));
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
}
|
||||
|
||||
Value options = argc > 1 ? argv[1] : Value();
|
||||
installErrorCause(state, obj, options);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
if (UNLIKELY(state.context()->vmInstance()->isErrorCreationCallbackRegistered())) {
|
||||
state.context()->vmInstance()->triggerErrorCreationCallback(state, obj);
|
||||
|
|
@ -79,14 +82,17 @@ static Value builtinErrorConstructor(ExecutionState& state, Value thisValue, siz
|
|||
Object* proto = Object::getPrototypeFromConstructor(state, newTarget.value(), [](ExecutionState& state, Context* constructorRealm) -> Object* { \
|
||||
return constructorRealm->globalObject()->lowerCaseErrorName##ErrorPrototype(); \
|
||||
}); \
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION \
|
||||
ErrorObject* obj = new errorName##ErrorObject(state, proto, String::emptyString); \
|
||||
Value message = argv[0]; \
|
||||
if (!message.isUndefined()) { \
|
||||
obj->defineOwnPropertyThrowsException(state, state.context()->staticStrings().message, \
|
||||
ObjectPropertyDescriptor(message.toString(state), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectStructurePropertyDescriptor::ConfigurablePresent))); \
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION \
|
||||
} \
|
||||
Value options = argc > 1 ? argv[1] : Value(); \
|
||||
installErrorCause(state, obj, options); \
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION \
|
||||
if (UNLIKELY(state.context()->vmInstance()->isErrorCreationCallbackRegistered())) { \
|
||||
state.context()->vmInstance()->triggerErrorCreationCallback(state, obj); \
|
||||
} \
|
||||
|
|
@ -110,6 +116,7 @@ static Value builtinAggregateErrorConstructor(ExecutionState& state, Value thisV
|
|||
Object* proto = Object::getPrototypeFromConstructor(state, newTarget.value(), [](ExecutionState& state, Context* constructorRealm) -> Object* {
|
||||
return constructorRealm->globalObject()->aggregateErrorPrototype();
|
||||
});
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
ErrorObject* O = new AggregateErrorObject(state, proto, String::emptyString);
|
||||
Value message = argv[1];
|
||||
// If message is not undefined, then
|
||||
|
|
@ -119,17 +126,21 @@ static Value builtinAggregateErrorConstructor(ExecutionState& state, Value thisV
|
|||
// Perform ! DefinePropertyOrThrow(O, "message", msgDesc).
|
||||
O->defineOwnPropertyThrowsException(state, state.context()->staticStrings().message,
|
||||
ObjectPropertyDescriptor(message.toString(state), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectStructurePropertyDescriptor::ConfigurablePresent)));
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
}
|
||||
|
||||
// Perform ? InstallErrorCause(O, options).
|
||||
Value options = argc > 2 ? argv[2] : Value();
|
||||
installErrorCause(state, O, options);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// Let errorsList be ? IterableToList(errors).
|
||||
auto errorsList = IteratorObject::iterableToList(state, argv[0]);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Perform ! DefinePropertyOrThrow(O, "errors", PropertyDescriptor { [[Configurable]]: true, [[Enumerable]]: false, [[Writable]]: true, [[Value]]: ! CreateArrayFromList(errorsList) }).
|
||||
O->defineOwnPropertyThrowsException(state, ObjectPropertyName(state, String::fromASCII("errors")),
|
||||
ObjectPropertyDescriptor(Value(Object::createArrayFromList(state, errorsList.size(), errorsList.data())), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectStructurePropertyDescriptor::ConfigurablePresent)));
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
if (UNLIKELY(state.context()->vmInstance()->isErrorCreationCallbackRegistered())) {
|
||||
state.context()->vmInstance()->triggerErrorCreationCallback(state, O);
|
||||
|
|
@ -141,14 +152,14 @@ static Value builtinAggregateErrorConstructor(ExecutionState& state, Value thisV
|
|||
|
||||
static Value builtinErrorThrowTypeError(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "");
|
||||
return Value();
|
||||
}
|
||||
|
||||
static Value builtinErrorToString(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (!thisValue.isObject())
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().Error.string(), true, state.context()->staticStrings().toString.string(), ErrorObject::Messages::GlobalObject_ThisNotObject);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Error.string(), true, state.context()->staticStrings().toString.string(), ErrorObject::Messages::GlobalObject_ThisNotObject);
|
||||
|
||||
Object* o = thisValue.toObject(state);
|
||||
|
||||
|
|
|
|||
|
|
@ -26,26 +26,26 @@
|
|||
|
||||
namespace Escargot {
|
||||
|
||||
#define RESOLVE_THIS_BINDING_TO_FINALIZATIONREGISTRY(NAME, BUILT_IN_METHOD) \
|
||||
if (!thisValue.isObject() || !thisValue.asObject()->isFinalizationRegistryObject()) { \
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().FinalizationRegistry.string(), true, state.context()->staticStrings().BUILT_IN_METHOD.string(), ErrorObject::Messages::GlobalObject_CalledOnIncompatibleReceiver); \
|
||||
} \
|
||||
#define RESOLVE_THIS_BINDING_TO_FINALIZATIONREGISTRY(NAME, BUILT_IN_METHOD) \
|
||||
if (!thisValue.isObject() || !thisValue.asObject()->isFinalizationRegistryObject()) { \
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().FinalizationRegistry.string(), true, state.context()->staticStrings().BUILT_IN_METHOD.string(), ErrorObject::Messages::GlobalObject_CalledOnIncompatibleReceiver); \
|
||||
} \
|
||||
FinalizationRegistryObject* NAME = thisValue.asObject()->asFinalizationRegistryObject();
|
||||
|
||||
static Value builtinFinalizationRegistryConstructor(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (!newTarget.hasValue()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ConstructorRequiresNew);
|
||||
return Value();
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ConstructorRequiresNew);
|
||||
}
|
||||
if (argc == 0 || !argv[0].isCallable()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "cleanup Callback is not callable");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "cleanup Callback is not callable");
|
||||
}
|
||||
|
||||
// Let finalizationRegistry be ? OrdinaryCreateFromConstructor(NewTarget, "%FinalizationRegistryPrototype%", « [[Realm]], [[CleanupCallback]], [[Cells]] »).
|
||||
Object* proto = Object::getPrototypeFromConstructor(state, newTarget.value(), [](ExecutionState& state, Context* constructorRealm) -> Object* {
|
||||
return constructorRealm->globalObject()->finalizationRegistryPrototype();
|
||||
});
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
return new FinalizationRegistryObject(state, proto, argv[0].asObject(), state.resolveCallee()->getFunctionRealm(state));
|
||||
}
|
||||
|
|
@ -55,10 +55,10 @@ static Value builtinfinalizationRegistryRegister(ExecutionState& state, Value th
|
|||
RESOLVE_THIS_BINDING_TO_FINALIZATIONREGISTRY(finalRegistry, stringRegister);
|
||||
|
||||
if (argc == 0 || !argv[0].isObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "target is not object");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "target is not object");
|
||||
}
|
||||
if (argv[0] == argv[1]) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "target and heldValue is the same");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "target and heldValue is the same");
|
||||
}
|
||||
|
||||
Optional<Object*> unregisterToken;
|
||||
|
|
@ -66,7 +66,7 @@ static Value builtinfinalizationRegistryRegister(ExecutionState& state, Value th
|
|||
if (argv[2].isObject()) {
|
||||
unregisterToken = argv[2].asObject();
|
||||
} else if (!argv[2].isUndefined()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "unregisterToken is not undefined");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "unregisterToken is not undefined");
|
||||
}
|
||||
}
|
||||
finalRegistry->setCell(argv[0].asObject(), argv[1], unregisterToken);
|
||||
|
|
@ -77,7 +77,7 @@ static Value builtinfinalizationRegistryUnregister(ExecutionState& state, Value
|
|||
{
|
||||
RESOLVE_THIS_BINDING_TO_FINALIZATIONREGISTRY(finalRegistry, unregister);
|
||||
if (argc == 0 || !argv[0].isObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "unregisterToken is not object");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "unregisterToken is not object");
|
||||
}
|
||||
return Value(finalRegistry->deleteCell(argv[0].asObject()));
|
||||
}
|
||||
|
|
@ -90,7 +90,7 @@ static Value builtinfinalizationRegistryCleanupSome(ExecutionState& state, Value
|
|||
Object* callback = nullptr;
|
||||
if (argc && !argv[0].isUndefined()) {
|
||||
if (!argv[0].isCallable()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "callback is not callable");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "callback is not callable");
|
||||
}
|
||||
callback = argv[0].asObject();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ static Value builtinFunctionConstructor(ExecutionState& state, Value thisValue,
|
|||
Value checkMSG = state.context()->securityPolicyCheckCallback()(state, false);
|
||||
if (!checkMSG.isEmpty()) {
|
||||
ASSERT(checkMSG.isString());
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::EvalError, checkMSG.asString());
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::EvalError, checkMSG.asString());
|
||||
return Value();
|
||||
}
|
||||
}
|
||||
|
|
@ -48,6 +48,7 @@ static Value builtinFunctionConstructor(ExecutionState& state, Value thisValue,
|
|||
size_t argumentVectorCount = argc > 1 ? argc - 1 : 0;
|
||||
Value sourceValue = argc >= 1 ? argv[argc - 1] : Value(String::emptyString);
|
||||
auto functionSource = FunctionObject::createDynamicFunctionScript(state, state.context()->staticStrings().anonymous, argumentVectorCount, argv, sourceValue, false, false, false, false);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// Let proto be ? GetPrototypeFromConstructor(newTarget, fallbackProto).
|
||||
if (!newTarget.hasValue()) {
|
||||
|
|
@ -56,6 +57,7 @@ static Value builtinFunctionConstructor(ExecutionState& state, Value thisValue,
|
|||
Object* proto = Object::getPrototypeFromConstructor(state, newTarget.value(), [](ExecutionState& state, Context* constructorRealm) -> Object* {
|
||||
return constructorRealm->globalObject()->functionPrototype();
|
||||
});
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
ScriptFunctionObject* result = new ScriptFunctionObject(state, proto, functionSource.codeBlock, functionSource.outerEnvironment, true, false);
|
||||
|
||||
|
|
@ -100,14 +102,14 @@ static Value builtinFunctionToString(ExecutionState& state, Value thisValue, siz
|
|||
}
|
||||
}
|
||||
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().Function.string(), true, state.context()->staticStrings().toString.string(), ErrorObject::Messages::GlobalObject_ThisNotFunctionObject);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Function.string(), true, state.context()->staticStrings().toString.string(), ErrorObject::Messages::GlobalObject_ThisNotFunctionObject);
|
||||
return Value();
|
||||
}
|
||||
|
||||
static Value builtinFunctionApply(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (!thisValue.isCallable()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().Function.string(), true, state.context()->staticStrings().apply.string(), ErrorObject::Messages::GlobalObject_ThisNotFunctionObject);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Function.string(), true, state.context()->staticStrings().apply.string(), ErrorObject::Messages::GlobalObject_ThisNotFunctionObject);
|
||||
}
|
||||
Value thisArg = argv[0];
|
||||
Value argArray = argv[1];
|
||||
|
|
@ -118,6 +120,7 @@ static Value builtinFunctionApply(ExecutionState& state, Value thisValue, size_t
|
|||
// TODO
|
||||
} else {
|
||||
argList = Object::createListFromArrayLike(state, argArray);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
arrlen = argList.size();
|
||||
arguments = argList.data();
|
||||
}
|
||||
|
|
@ -128,7 +131,7 @@ static Value builtinFunctionApply(ExecutionState& state, Value thisValue, size_t
|
|||
static Value builtinFunctionCall(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (!thisValue.isCallable()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().Function.string(), true, state.context()->staticStrings().apply.string(), ErrorObject::Messages::GlobalObject_ThisNotFunctionObject);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Function.string(), true, state.context()->staticStrings().apply.string(), ErrorObject::Messages::GlobalObject_ThisNotFunctionObject);
|
||||
}
|
||||
Value thisArg = argv[0];
|
||||
size_t arrlen = argc > 0 ? argc - 1 : 0;
|
||||
|
|
@ -145,7 +148,7 @@ static Value builtinFunctionBind(ExecutionState& state, Value thisValue, size_t
|
|||
{
|
||||
// If IsCallable(Target) is false, throw a TypeError exception.
|
||||
if (!thisValue.isCallable()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().Function.string(), true, state.context()->staticStrings().bind.string(), ErrorObject::Messages::GlobalObject_ThisNotFunctionObject);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Function.string(), true, state.context()->staticStrings().bind.string(), ErrorObject::Messages::GlobalObject_ThisNotFunctionObject);
|
||||
}
|
||||
|
||||
// Let Target be the this value.
|
||||
|
|
@ -164,6 +167,7 @@ static Value builtinFunctionBind(ExecutionState& state, Value thisValue, size_t
|
|||
if (targetHasLength) {
|
||||
// Let targetLen be Get(Target, "length").
|
||||
Value targetLen = target->get(state, ObjectPropertyName(state.context()->staticStrings().length)).value(state, target);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// If Type(targetLen) is not Number, let L be 0.
|
||||
// Else Let targetLen be ToInteger(targetLen).
|
||||
// Let L be the larger of 0 and the result of targetLen minus the number of elements of args.
|
||||
|
|
@ -177,6 +181,7 @@ static Value builtinFunctionBind(ExecutionState& state, Value thisValue, size_t
|
|||
|
||||
// Let targetName be Get(Target, "name").
|
||||
Value targetName = target->get(state, ObjectPropertyName(state.context()->staticStrings().name)).value(state, target);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// If Type(targetName) is not String, let targetName be the empty string.
|
||||
if (!targetName.isString()) {
|
||||
targetName = String::emptyString;
|
||||
|
|
@ -200,7 +205,9 @@ static Value builtinFunctionHasInstanceOf(ExecutionState& state, Value thisValue
|
|||
if (!thisValue.isObject()) {
|
||||
return Value(false);
|
||||
}
|
||||
return Value(thisValue.asObject()->hasInstance(state, argv[0]));
|
||||
Value result = Value(thisValue.asObject()->hasInstance(state, argv[0]));
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
return result;
|
||||
}
|
||||
|
||||
static Value builtinCallerAndArgumentsGetterSetter(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
|
|
@ -232,7 +239,7 @@ static Value builtinCallerAndArgumentsGetterSetter(ExecutionState& state, Value
|
|||
}
|
||||
|
||||
if (needThrow) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "'caller' and 'arguments' restrict properties may not be accessed on strict mode functions or the arguments objects for calls to them");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "'caller' and 'arguments' restrict properties may not be accessed on strict mode functions or the arguments objects for calls to them");
|
||||
}
|
||||
|
||||
bool inStrict = false;
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ static Value builtinGeneratorFunction(ExecutionState& state, Value thisValue, si
|
|||
size_t argumentVectorCount = argc > 1 ? argc - 1 : 0;
|
||||
Value sourceValue = argc >= 1 ? argv[argc - 1] : Value(String::emptyString);
|
||||
auto functionSource = FunctionObject::createDynamicFunctionScript(state, state.context()->staticStrings().anonymous, argumentVectorCount, argv, sourceValue, false, true, false, false);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// Let proto be ? GetPrototypeFromConstructor(newTarget, fallbackProto).
|
||||
if (!newTarget.hasValue()) {
|
||||
|
|
@ -40,6 +41,7 @@ static Value builtinGeneratorFunction(ExecutionState& state, Value thisValue, si
|
|||
Object* proto = Object::getPrototypeFromConstructor(state, newTarget.value(), [](ExecutionState& state, Context* constructorRealm) -> Object* {
|
||||
return constructorRealm->globalObject()->generator();
|
||||
});
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
return new ScriptGeneratorFunctionObject(state, proto, functionSource.codeBlock, functionSource.outerEnvironment);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ static Value builtinIntlCollatorCompare(ExecutionState& state, Value thisValue,
|
|||
{
|
||||
FunctionObject* callee = state.resolveCallee();
|
||||
if (!callee->hasInternalSlot() || !callee->internalSlot()->hasOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().lazyInitializedCollator()))) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
}
|
||||
|
||||
Object* colllator = callee->asObject();
|
||||
|
|
@ -109,7 +109,7 @@ static Value builtinIntlCollatorCompare(ExecutionState& state, Value thisValue,
|
|||
static Value builtinIntlCollatorCompareGetter(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (!thisValue.isObject() || !thisValue.asObject()->hasInternalSlot() || !thisValue.asObject()->internalSlot()->hasOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().lazyInitializedCollator()))) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
}
|
||||
|
||||
Object* internalSlot = thisValue.asObject()->internalSlot();
|
||||
|
|
@ -129,7 +129,7 @@ static Value builtinIntlCollatorCompareGetter(ExecutionState& state, Value thisV
|
|||
static Value builtinIntlCollatorResolvedOptions(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (!thisValue.isObject() || !thisValue.asObject()->hasInternalSlot() || !thisValue.asObject()->internalSlot()->hasOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().lazyInitializedCollator()))) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
}
|
||||
|
||||
Object* internalSlot = thisValue.asObject()->internalSlot();
|
||||
|
|
@ -192,7 +192,7 @@ static Value builtinIntlDateTimeFormatFormat(ExecutionState& state, Value thisVa
|
|||
{
|
||||
FunctionObject* callee = state.resolveCallee();
|
||||
if (!callee->internalSlot() || !callee->internalSlot()->isIntlDateTimeFormatObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
}
|
||||
|
||||
IntlDateTimeFormatObject* dateTimeFormat = callee->internalSlot()->asIntlDateTimeFormatObject();
|
||||
|
|
@ -210,7 +210,7 @@ static Value builtinIntlDateTimeFormatFormat(ExecutionState& state, Value thisVa
|
|||
static Value builtinIntlDateTimeFormatFormatGetter(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (!thisValue.isObject() || !thisValue.asObject()->isIntlDateTimeFormatObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
}
|
||||
|
||||
IntlDateTimeFormatObject* dtf = thisValue.asObject()->asIntlDateTimeFormatObject();
|
||||
|
|
@ -230,7 +230,7 @@ static Value builtinIntlDateTimeFormatFormatToParts(ExecutionState& state, Value
|
|||
// If Type(dtf) is not Object, throw a TypeError exception.
|
||||
// If dtf does not have an [[InitializedDateTimeFormat]] internal slot, throw a TypeError exception.
|
||||
if (!thisValue.isObject() || !thisValue.asObject()->isIntlDateTimeFormatObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
}
|
||||
IntlDateTimeFormatObject* dtf = thisValue.asObject()->asIntlDateTimeFormatObject();
|
||||
Value date = argv[0];
|
||||
|
|
@ -261,7 +261,7 @@ static void setFormatOpt(ExecutionState& state, Object* internalSlot, Object* re
|
|||
static Value builtinIntlDateTimeFormatResolvedOptions(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (!thisValue.isObject() || !thisValue.asObject()->isIntlDateTimeFormatObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
}
|
||||
IntlDateTimeFormatObject* intlDateTimeFormatObject = thisValue.asObject()->asIntlDateTimeFormatObject();
|
||||
Object* result = new Object(state);
|
||||
|
|
@ -320,7 +320,7 @@ static Value builtinIntlNumberFormatFormat(ExecutionState& state, Value thisValu
|
|||
{
|
||||
FunctionObject* callee = state.resolveCallee();
|
||||
if (!callee->hasInternalSlot() || !callee->internalSlot()->hasOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().lazyInitializedNumberFormat()))) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
}
|
||||
|
||||
Object* numberFormat = callee->asObject();
|
||||
|
|
@ -339,7 +339,7 @@ static Value builtinIntlNumberFormatFormat(ExecutionState& state, Value thisValu
|
|||
static Value builtinIntlNumberFormatFormatGetter(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (!thisValue.isObject() || !thisValue.asObject()->hasInternalSlot() || !thisValue.asObject()->internalSlot()->hasOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().lazyInitializedNumberFormat()))) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
}
|
||||
|
||||
Object* internalSlot = thisValue.asObject()->internalSlot();
|
||||
|
|
@ -386,7 +386,7 @@ static Value builtinIntlNumberFormatConstructor(ExecutionState& state, Value thi
|
|||
static Value builtinIntlNumberFormatResolvedOptions(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (!thisValue.isObject() || !thisValue.asObject()->hasInternalSlot() || !thisValue.asObject()->internalSlot()->hasOwnProperty(state, state.context()->staticStrings().lazyInitializedNumberFormat())) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
}
|
||||
|
||||
Object* internalSlot = thisValue.asObject()->internalSlot();
|
||||
|
|
@ -418,7 +418,7 @@ static Value builtinIntlNumberFormatFormatToParts(ExecutionState& state, Value t
|
|||
// If Type(nf) is not Object, throw a TypeError exception.
|
||||
// If nf does not have an [[InitializedNumberFormat]] internal slot, throw a TypeError exception.
|
||||
if (!thisValue.isObject() || !thisValue.asObject()->hasInternalSlot() || !thisValue.asObject()->internalSlot()->hasOwnProperty(state, state.context()->staticStrings().lazyInitializedNumberFormat())) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
}
|
||||
// Let x be ? ToNumeric(value).
|
||||
double x = argv[0].toNumber(state);
|
||||
|
|
@ -448,15 +448,14 @@ static Value builtinIntlPluralRulesConstructor(ExecutionState& state, Value this
|
|||
{
|
||||
// If NewTarget is undefined, throw a TypeError exception.
|
||||
if (!newTarget) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ConstructorRequiresNew);
|
||||
return Value();
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ConstructorRequiresNew);
|
||||
}
|
||||
|
||||
#if defined(ENABLE_RUNTIME_ICU_BINDER)
|
||||
UVersionInfo versionArray;
|
||||
u_getVersion(versionArray);
|
||||
if (versionArray[0] < 60) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Intl.PluralRules needs 60+ version of ICU");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Intl.PluralRules needs 60+ version of ICU");
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -477,7 +476,7 @@ static Value builtinIntlPluralRulesSelect(ExecutionState& state, Value thisValue
|
|||
// If Type(pr) is not Object, throw a TypeError exception.
|
||||
// If pr does not have an [[InitializedPluralRules]] internal slot, throw a TypeError exception.
|
||||
if (!thisValue.isObject() || !thisValue.asObject()->isIntlPluralRulesObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
}
|
||||
// Let n be ? ToNumber(value).
|
||||
double n = argv[0].toNumber(state);
|
||||
|
|
@ -491,7 +490,7 @@ static Value builtinIntlPluralRulesResolvedOptions(ExecutionState& state, Value
|
|||
// If Type(pr) is not Object, throw a TypeError exception.
|
||||
// If pr does not have an [[InitializedPluralRules]] internal slot, throw a TypeError exception.
|
||||
if (!thisValue.isObject() || !thisValue.asObject()->isIntlPluralRulesObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
}
|
||||
|
||||
IntlPluralRulesObject* pr = thisValue.asObject()->asIntlPluralRulesObject();
|
||||
|
|
@ -570,15 +569,14 @@ static Value builtinIntlLocaleConstructor(ExecutionState& state, Value thisValue
|
|||
{
|
||||
// If NewTarget is undefined, throw a TypeError exception.
|
||||
if (!newTarget) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ConstructorRequiresNew);
|
||||
return Value();
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ConstructorRequiresNew);
|
||||
}
|
||||
|
||||
Value tagValue = argv[0];
|
||||
|
||||
// If Type(tag) is not String or Object, throw a TypeError exception.
|
||||
if (!tagValue.isObject() && !tagValue.isString()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "First argument of Intl.Locale should be String or Object");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "First argument of Intl.Locale should be String or Object");
|
||||
}
|
||||
|
||||
String* tag;
|
||||
|
|
@ -614,7 +612,7 @@ static Value builtinIntlLocaleToString(ExecutionState& state, Value thisValue, s
|
|||
// If Type(loc) is not Object or loc does not have an [[InitializedLocale]] internal slot, then
|
||||
if (!loc.isObject() || !loc.asObject()->isIntlLocaleObject()) {
|
||||
// Throw a TypeError exception.
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
}
|
||||
// Return loc.[[Locale]].
|
||||
return loc.asObject()->asIntlLocaleObject()->locale();
|
||||
|
|
@ -626,7 +624,7 @@ static Value builtinIntlLocaleBaseNameGetter(ExecutionState& state, Value thisVa
|
|||
// If Type(loc) is not Object or loc does not have an [[InitializedLocale]] internal slot, then
|
||||
if (!loc.isObject() || !loc.asObject()->isIntlLocaleObject()) {
|
||||
// Throw a TypeError exception.
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
}
|
||||
|
||||
return loc.asObject()->asIntlLocaleObject()->baseName();
|
||||
|
|
@ -638,7 +636,7 @@ static Value builtinIntlLocaleCalendarGetter(ExecutionState& state, Value thisVa
|
|||
// If Type(loc) is not Object or loc does not have an [[InitializedLocale]] internal slot, then
|
||||
if (!loc.isObject() || !loc.asObject()->isIntlLocaleObject()) {
|
||||
// Throw a TypeError exception.
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
}
|
||||
|
||||
return loc.asObject()->asIntlLocaleObject()->calendar().hasValue() ? loc.asObject()->asIntlLocaleObject()->calendar().value() : Value();
|
||||
|
|
@ -650,7 +648,7 @@ static Value builtinIntlLocaleCaseFirstGetter(ExecutionState& state, Value thisV
|
|||
// If Type(loc) is not Object or loc does not have an [[InitializedLocale]] internal slot, then
|
||||
if (!loc.isObject() || !loc.asObject()->isIntlLocaleObject()) {
|
||||
// Throw a TypeError exception.
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
}
|
||||
|
||||
return loc.asObject()->asIntlLocaleObject()->caseFirst().hasValue() ? loc.asObject()->asIntlLocaleObject()->caseFirst().value() : Value();
|
||||
|
|
@ -662,7 +660,7 @@ static Value builtinIntlLocaleCollationGetter(ExecutionState& state, Value thisV
|
|||
// If Type(loc) is not Object or loc does not have an [[InitializedLocale]] internal slot, then
|
||||
if (!loc.isObject() || !loc.asObject()->isIntlLocaleObject()) {
|
||||
// Throw a TypeError exception.
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
}
|
||||
|
||||
return loc.asObject()->asIntlLocaleObject()->collation().hasValue() ? loc.asObject()->asIntlLocaleObject()->collation().value() : Value();
|
||||
|
|
@ -674,7 +672,7 @@ static Value builtinIntlLocaleHourCycleGetter(ExecutionState& state, Value thisV
|
|||
// If Type(loc) is not Object or loc does not have an [[InitializedLocale]] internal slot, then
|
||||
if (!loc.isObject() || !loc.asObject()->isIntlLocaleObject()) {
|
||||
// Throw a TypeError exception.
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
}
|
||||
|
||||
return loc.asObject()->asIntlLocaleObject()->hourCycle().hasValue() ? loc.asObject()->asIntlLocaleObject()->hourCycle().value() : Value();
|
||||
|
|
@ -686,7 +684,7 @@ static Value builtinIntlLocaleNumericGetter(ExecutionState& state, Value thisVal
|
|||
// If Type(loc) is not Object or loc does not have an [[InitializedLocale]] internal slot, then
|
||||
if (!loc.isObject() || !loc.asObject()->isIntlLocaleObject()) {
|
||||
// Throw a TypeError exception.
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
}
|
||||
|
||||
return loc.asObject()->asIntlLocaleObject()->numeric().hasValue() ? Value(loc.asObject()->asIntlLocaleObject()->numeric().value()->equals("true")) : Value(false);
|
||||
|
|
@ -698,7 +696,7 @@ static Value builtinIntlLocaleNumberingSystemGetter(ExecutionState& state, Value
|
|||
// If Type(loc) is not Object or loc does not have an [[InitializedLocale]] internal slot, then
|
||||
if (!loc.isObject() || !loc.asObject()->isIntlLocaleObject()) {
|
||||
// Throw a TypeError exception.
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
}
|
||||
|
||||
return loc.asObject()->asIntlLocaleObject()->numberingSystem().hasValue() ? loc.asObject()->asIntlLocaleObject()->numberingSystem().value() : Value();
|
||||
|
|
@ -710,7 +708,7 @@ static Value builtinIntlLocaleLanguageGetter(ExecutionState& state, Value thisVa
|
|||
// If Type(loc) is not Object or loc does not have an [[InitializedLocale]] internal slot, then
|
||||
if (!loc.isObject() || !loc.asObject()->isIntlLocaleObject()) {
|
||||
// Throw a TypeError exception.
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
}
|
||||
|
||||
return loc.asObject()->asIntlLocaleObject()->language();
|
||||
|
|
@ -722,7 +720,7 @@ static Value builtinIntlLocaleScriptGetter(ExecutionState& state, Value thisValu
|
|||
// If Type(loc) is not Object or loc does not have an [[InitializedLocale]] internal slot, then
|
||||
if (!loc.isObject() || !loc.asObject()->isIntlLocaleObject()) {
|
||||
// Throw a TypeError exception.
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
}
|
||||
|
||||
return loc.asObject()->asIntlLocaleObject()->script();
|
||||
|
|
@ -734,7 +732,7 @@ static Value builtinIntlLocaleRegionGetter(ExecutionState& state, Value thisValu
|
|||
// If Type(loc) is not Object or loc does not have an [[InitializedLocale]] internal slot, then
|
||||
if (!loc.isObject() || !loc.asObject()->isIntlLocaleObject()) {
|
||||
// Throw a TypeError exception.
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
}
|
||||
|
||||
return loc.asObject()->asIntlLocaleObject()->region();
|
||||
|
|
@ -777,7 +775,7 @@ static Value builtinIntlLocaleMaximize(ExecutionState& state, Value thisValue, s
|
|||
// If Type(loc) is not Object or loc does not have an [[InitializedLocale]] internal slot, then
|
||||
if (!loc.isObject() || !loc.asObject()->isIntlLocaleObject()) {
|
||||
// Throw a TypeError exception.
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
}
|
||||
|
||||
// Let maximal be the result of the Add Likely Subtags algorithm applied to loc.[[Locale]]. If an error is signaled, set maximal to loc.[[Locale]].
|
||||
|
|
@ -796,7 +794,7 @@ static Value builtinIntlLocaleMaximize(ExecutionState& state, Value thisValue, s
|
|||
return new IntlLocaleObject(state, sb.finalize(), nullptr);
|
||||
|
||||
} else if (status != U_BUFFER_OVERFLOW_ERROR) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, "Unexpected error is occured while parsing locale");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::RangeError, "Unexpected error is occured while parsing locale");
|
||||
}
|
||||
status = U_ZERO_ERROR;
|
||||
char* newBuf = (char*)alloca(len + 1);
|
||||
|
|
@ -816,7 +814,7 @@ static Value builtinIntlLocaleMinimize(ExecutionState& state, Value thisValue, s
|
|||
// If Type(loc) is not Object or loc does not have an [[InitializedLocale]] internal slot, then
|
||||
if (!loc.isObject() || !loc.asObject()->isIntlLocaleObject()) {
|
||||
// Throw a TypeError exception.
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
}
|
||||
|
||||
// Let minimal be the result of the Remove Likely Subtags algorithm applied to loc.[[Locale]]. If an error is signaled, set minimal to loc.[[Locale]].
|
||||
|
|
@ -834,7 +832,7 @@ static Value builtinIntlLocaleMinimize(ExecutionState& state, Value thisValue, s
|
|||
sb.appendSubString(locale, localeObject->baseName()->length(), locale->length());
|
||||
return new IntlLocaleObject(state, sb.finalize(), nullptr);
|
||||
} else if (status != U_BUFFER_OVERFLOW_ERROR) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, "Unexpected error is occured while parsing locale");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::RangeError, "Unexpected error is occured while parsing locale");
|
||||
}
|
||||
status = U_ZERO_ERROR;
|
||||
char* newBuf = (char*)alloca(len + 1);
|
||||
|
|
@ -851,7 +849,7 @@ static Value builtinIntlLocaleMinimize(ExecutionState& state, Value thisValue, s
|
|||
static Value builtinIntlLocaleCalendarsGetter(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (!thisValue.isObject() || !thisValue.asObject()->isIntlLocaleObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
}
|
||||
return thisValue.asObject()->asIntlLocaleObject()->calendars(state);
|
||||
}
|
||||
|
|
@ -859,7 +857,7 @@ static Value builtinIntlLocaleCalendarsGetter(ExecutionState& state, Value thisV
|
|||
static Value builtinIntlLocaleCollationsGetter(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (!thisValue.isObject() || !thisValue.asObject()->isIntlLocaleObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
}
|
||||
return thisValue.asObject()->asIntlLocaleObject()->collations(state);
|
||||
}
|
||||
|
|
@ -867,7 +865,7 @@ static Value builtinIntlLocaleCollationsGetter(ExecutionState& state, Value this
|
|||
static Value builtinIntlLocaleHourCyclesGetter(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (!thisValue.isObject() || !thisValue.asObject()->isIntlLocaleObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
}
|
||||
return thisValue.asObject()->asIntlLocaleObject()->hourCycles(state);
|
||||
}
|
||||
|
|
@ -875,7 +873,7 @@ static Value builtinIntlLocaleHourCyclesGetter(ExecutionState& state, Value this
|
|||
static Value builtinIntlLocaleNumberingSystemsGetter(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (!thisValue.isObject() || !thisValue.asObject()->isIntlLocaleObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
}
|
||||
return thisValue.asObject()->asIntlLocaleObject()->numberingSystems(state);
|
||||
}
|
||||
|
|
@ -883,7 +881,7 @@ static Value builtinIntlLocaleNumberingSystemsGetter(ExecutionState& state, Valu
|
|||
static Value builtinIntlLocaleTextInfoGetter(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (!thisValue.isObject() || !thisValue.asObject()->isIntlLocaleObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
}
|
||||
return thisValue.asObject()->asIntlLocaleObject()->textInfo(state);
|
||||
}
|
||||
|
|
@ -891,7 +889,7 @@ static Value builtinIntlLocaleTextInfoGetter(ExecutionState& state, Value thisVa
|
|||
static Value builtinIntlLocaleWeekInfoGetter(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (!thisValue.isObject() || !thisValue.asObject()->isIntlLocaleObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
}
|
||||
return thisValue.asObject()->asIntlLocaleObject()->weekInfo(state);
|
||||
}
|
||||
|
|
@ -899,7 +897,7 @@ static Value builtinIntlLocaleWeekInfoGetter(ExecutionState& state, Value thisVa
|
|||
static Value builtinIntlLocaleTimeZonesGetter(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (!thisValue.isObject() || !thisValue.asObject()->isIntlLocaleObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
}
|
||||
return thisValue.asObject()->asIntlLocaleObject()->timeZones(state);
|
||||
}
|
||||
|
|
@ -909,15 +907,14 @@ static Value builtinIntlRelativeTimeFormatConstructor(ExecutionState& state, Val
|
|||
{
|
||||
// If NewTarget is undefined, throw a TypeError exception.
|
||||
if (!newTarget) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ConstructorRequiresNew);
|
||||
return Value();
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ConstructorRequiresNew);
|
||||
}
|
||||
|
||||
#if defined(ENABLE_RUNTIME_ICU_BINDER)
|
||||
UVersionInfo versionArray;
|
||||
u_getVersion(versionArray);
|
||||
if (versionArray[0] < 64) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Intl.RelativeTimeFormat needs 64+ version of ICU");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Intl.RelativeTimeFormat needs 64+ version of ICU");
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -934,7 +931,7 @@ static Value builtinIntlRelativeTimeFormatConstructor(ExecutionState& state, Val
|
|||
static Value builtinIntlRelativeTimeFormatResolvedOptions(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (!thisValue.isObject() || !thisValue.asObject()->isIntlRelativeTimeFormatObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
}
|
||||
|
||||
IntlRelativeTimeFormatObject* r = thisValue.asObject()->asIntlRelativeTimeFormatObject();
|
||||
|
|
@ -968,7 +965,7 @@ static Value builtinIntlRelativeTimeFormatSupportedLocalesOf(ExecutionState& sta
|
|||
static Value builtinIntlRelativeTimeFormatFormat(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (!thisValue.isObject() || !thisValue.asObject()->isIntlRelativeTimeFormatObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
}
|
||||
|
||||
// Let relativeTimeFormat be the this value.
|
||||
|
|
@ -984,7 +981,7 @@ static Value builtinIntlRelativeTimeFormatFormat(ExecutionState& state, Value th
|
|||
static Value builtinIntlRelativeTimeFormatFormatToParts(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (!thisValue.isObject() || !thisValue.asObject()->isIntlRelativeTimeFormatObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
}
|
||||
|
||||
// Let relativeTimeFormat be the this value.
|
||||
|
|
@ -1004,8 +1001,7 @@ static Value builtinIntlDisplayNamesConstructor(ExecutionState& state, Value thi
|
|||
// https://402.ecma-international.org/8.0/#sec-Intl.DisplayNames
|
||||
// If NewTarget is undefined, throw a TypeError exception.
|
||||
if (!newTarget) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ConstructorRequiresNew);
|
||||
return Value();
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ConstructorRequiresNew);
|
||||
}
|
||||
|
||||
Object* proto = Object::getPrototypeFromConstructor(state, newTarget.value(), [](ExecutionState& state, Context* realm) -> Object* {
|
||||
|
|
@ -1017,7 +1013,7 @@ static Value builtinIntlDisplayNamesConstructor(ExecutionState& state, Value thi
|
|||
static Value builtinIntlDisplayNamesOf(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (!thisValue.isObject() || !thisValue.asObject()->isIntlDisplayNamesObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
}
|
||||
|
||||
IntlDisplayNamesObject* r = thisValue.asObject()->asIntlDisplayNamesObject();
|
||||
|
|
@ -1027,7 +1023,7 @@ static Value builtinIntlDisplayNamesOf(ExecutionState& state, Value thisValue, s
|
|||
static Value builtinIntlDisplayNamesResolvedOptions(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (!thisValue.isObject() || !thisValue.asObject()->isIntlDisplayNamesObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
}
|
||||
|
||||
IntlDisplayNamesObject* r = thisValue.asObject()->asIntlDisplayNamesObject();
|
||||
|
|
@ -1049,8 +1045,7 @@ static Value builtinIntlListFormatConstructor(ExecutionState& state, Value thisV
|
|||
{
|
||||
// If NewTarget is undefined, throw a TypeError exception.
|
||||
if (!newTarget) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ConstructorRequiresNew);
|
||||
return Value();
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ConstructorRequiresNew);
|
||||
}
|
||||
|
||||
Object* proto = Object::getPrototypeFromConstructor(state, newTarget.value(), [](ExecutionState& state, Context* realm) -> Object* {
|
||||
|
|
@ -1080,7 +1075,7 @@ static Value builtinIntlListFormatSupportedLocalesOf(ExecutionState& state, Valu
|
|||
static Value builtinIntlListFormatResolvedOptions(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (!thisValue.isObject() || !thisValue.asObject()->isIntlListFormatObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
}
|
||||
|
||||
IntlListFormatObject* r = thisValue.asObject()->asIntlListFormatObject();
|
||||
|
|
@ -1097,7 +1092,7 @@ static Value builtinIntlListFormatResolvedOptions(ExecutionState& state, Value t
|
|||
static Value builtinIntlListFormatFormat(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (!thisValue.isObject() || !thisValue.asObject()->isIntlListFormatObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
}
|
||||
|
||||
IntlListFormatObject* r = thisValue.asObject()->asIntlListFormatObject();
|
||||
|
|
@ -1107,7 +1102,7 @@ static Value builtinIntlListFormatFormat(ExecutionState& state, Value thisValue,
|
|||
static Value builtinIntlListFormatFormatToParts(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (!thisValue.isObject() || !thisValue.asObject()->isIntlListFormatObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Method called on incompatible receiver");
|
||||
}
|
||||
|
||||
IntlListFormatObject* r = thisValue.asObject()->asIntlListFormatObject();
|
||||
|
|
|
|||
|
|
@ -30,8 +30,7 @@ namespace Escargot {
|
|||
static Value builtinMapConstructor(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (!newTarget.hasValue()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ConstructorRequiresNew);
|
||||
return Value();
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ConstructorRequiresNew);
|
||||
}
|
||||
|
||||
// Let map be ? OrdinaryCreateFromConstructor(NewTarget, "%MapPrototype%", « [[MapData]] »).
|
||||
|
|
@ -39,6 +38,7 @@ static Value builtinMapConstructor(ExecutionState& state, Value thisValue, size_
|
|||
Object* proto = Object::getPrototypeFromConstructor(state, newTarget.value(), [](ExecutionState& state, Context* constructorRealm) -> Object* {
|
||||
return constructorRealm->globalObject()->mapPrototype();
|
||||
});
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
MapObject* map = new MapObject(state, proto);
|
||||
|
||||
// If iterable is not present, or is either undefined or null, return map.
|
||||
|
|
@ -50,51 +50,65 @@ static Value builtinMapConstructor(ExecutionState& state, Value thisValue, size_
|
|||
|
||||
// Let adder be ? Get(map, "set").
|
||||
Value adder = map->Object::get(state, ObjectPropertyName(state.context()->staticStrings().set)).value(state, map);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// If IsCallable(adder) is false, throw a TypeError exception.
|
||||
if (!adder.isCallable()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::NOT_Callable);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::NOT_Callable);
|
||||
}
|
||||
|
||||
// Let iteratorRecord be ? GetIterator(iterable).
|
||||
auto iteratorRecord = IteratorObject::getIterator(state, iterable);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
while (true) {
|
||||
auto next = IteratorObject::iteratorStep(state, iteratorRecord);
|
||||
if (!next.hasValue()) {
|
||||
return map;
|
||||
}
|
||||
{
|
||||
auto next = IteratorObject::iteratorStep(state, iteratorRecord);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (!next.hasValue()) {
|
||||
return map;
|
||||
}
|
||||
|
||||
Value nextItem = IteratorObject::iteratorValue(state, next.value());
|
||||
if (!nextItem.isObject()) {
|
||||
ErrorObject* errorobj = ErrorObject::createError(state, ErrorCode::TypeError, new ASCIIString("TypeError"));
|
||||
return IteratorObject::iteratorClose(state, iteratorRecord, errorobj, true);
|
||||
}
|
||||
Value nextItem = IteratorObject::iteratorValue(state, next.value());
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (!nextItem.isObject()) {
|
||||
ErrorObject* errorobj = ErrorObject::createError(state, ErrorCode::TypeError, new ASCIIString("TypeError"));
|
||||
return IteratorObject::iteratorClose(state, iteratorRecord, errorobj, true);
|
||||
}
|
||||
|
||||
try {
|
||||
// Let k be Get(nextItem, "0").
|
||||
// If k is an abrupt completion, return ? IteratorClose(iter, k).
|
||||
Value k = nextItem.asObject()->getIndexedProperty(state, Value(0)).value(state, nextItem);
|
||||
if (state.hasPendingException())
|
||||
goto IfAbrupt;
|
||||
// Let v be Get(nextItem, "1").
|
||||
// If v is an abrupt completion, return ? IteratorClose(iter, v).
|
||||
Value v = nextItem.asObject()->getIndexedProperty(state, Value(1)).value(state, nextItem);
|
||||
if (state.hasPendingException())
|
||||
goto IfAbrupt;
|
||||
|
||||
// Let status be Call(adder, map, « k.[[Value]], v.[[Value]] »).
|
||||
Value argv[2] = { k, v };
|
||||
Object::call(state, adder, map, 2, argv);
|
||||
} catch (const Value& v) {
|
||||
// we should save thrown value bdwgc cannot track thrown value
|
||||
Value exceptionValue = v;
|
||||
// If status is an abrupt completion, return ? IteratorClose(iteratorRecord, status).
|
||||
return IteratorObject::iteratorClose(state, iteratorRecord, exceptionValue, true);
|
||||
if (state.hasPendingException())
|
||||
goto IfAbrupt;
|
||||
continue;
|
||||
}
|
||||
|
||||
IfAbrupt : {
|
||||
ASSERT(state.hasPendingException());
|
||||
// we should save thrown value bdwgc cannot track thrown value
|
||||
Value exceptionValue = state.detachPendingException();
|
||||
// If status is an abrupt completion, return ? IteratorClose(iteratorRecord, status).
|
||||
return IteratorObject::iteratorClose(state, iteratorRecord, exceptionValue, true);
|
||||
}
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
#define RESOLVE_THIS_BINDING_TO_MAP(NAME, OBJ, BUILT_IN_METHOD) \
|
||||
if (!thisValue.isObject() || !thisValue.asObject()->isMapObject()) { \
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().OBJ.string(), true, state.context()->staticStrings().BUILT_IN_METHOD.string(), ErrorObject::Messages::GlobalObject_CalledOnIncompatibleReceiver); \
|
||||
} \
|
||||
#define RESOLVE_THIS_BINDING_TO_MAP(NAME, OBJ, BUILT_IN_METHOD) \
|
||||
if (!thisValue.isObject() || !thisValue.asObject()->isMapObject()) { \
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().OBJ.string(), true, state.context()->staticStrings().BUILT_IN_METHOD.string(), ErrorObject::Messages::GlobalObject_CalledOnIncompatibleReceiver); \
|
||||
} \
|
||||
MapObject* NAME = thisValue.asObject()->asMapObject();
|
||||
|
||||
static Value builtinMapClear(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
|
|
@ -139,7 +153,7 @@ static Value builtinMapForEach(ExecutionState& state, Value thisValue, size_t ar
|
|||
Value callbackfn = argv[0];
|
||||
// If IsCallable(callbackfn) is false, throw a TypeError exception.
|
||||
if (!callbackfn.isCallable()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().Map.string(), true, state.context()->staticStrings().forEach.string(), ErrorObject::Messages::GlobalObject_CallbackNotCallable);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Map.string(), true, state.context()->staticStrings().forEach.string(), ErrorObject::Messages::GlobalObject_CallbackNotCallable);
|
||||
}
|
||||
// If thisArg was supplied, let T be thisArg; else let T be undefined.
|
||||
Value T;
|
||||
|
|
@ -155,6 +169,7 @@ static Value builtinMapForEach(ExecutionState& state, Value thisValue, size_t ar
|
|||
// Perform ? Call(callbackfn, T, « e.[[Value]], e.[[Key]], M »).
|
||||
Value argv[3] = { Value(entries[i].second), Value(entries[i].first), Value(M) };
|
||||
Object::call(state, callbackfn, T, 3, argv);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -188,7 +203,7 @@ static Value builtinMapSizeGetter(ExecutionState& state, Value thisValue, size_t
|
|||
static Value builtinMapIteratorNext(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (!thisValue.isObject() || !thisValue.asObject()->isMapIteratorObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().MapIterator.string(), true, state.context()->staticStrings().next.string(), ErrorObject::Messages::GlobalObject_CalledOnIncompatibleReceiver);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().MapIterator.string(), true, state.context()->staticStrings().next.string(), ErrorObject::Messages::GlobalObject_CalledOnIncompatibleReceiver);
|
||||
}
|
||||
MapIteratorObject* iter = thisValue.asObject()->asIteratorObject()->asMapIteratorObject();
|
||||
return iter->next(state);
|
||||
|
|
|
|||
|
|
@ -43,8 +43,10 @@ static Value builtinMathMax(ExecutionState& state, Value thisValue, size_t argc,
|
|||
}
|
||||
|
||||
double maxValue = argv[0].toNumber(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
for (unsigned i = 1; i < argc; i++) {
|
||||
double value = argv[i].toNumber(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (std::isnan(value))
|
||||
is_NaN = true;
|
||||
if (value > maxValue || (!value && !maxValue && !std::signbit(value)))
|
||||
|
|
@ -64,8 +66,10 @@ static Value builtinMathMin(ExecutionState& state, Value thisValue, size_t argc,
|
|||
|
||||
bool hasNaN = false;
|
||||
double minValue = argv[0].toNumber(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
for (unsigned i = 1; i < argc; i++) {
|
||||
double value = argv[i].toNumber(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (std::isnan(value)) {
|
||||
hasNaN = true;
|
||||
}
|
||||
|
|
@ -82,6 +86,7 @@ static Value builtinMathMin(ExecutionState& state, Value thisValue, size_t argc,
|
|||
static Value builtinMathRound(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
double x = argv[0].toNumber(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (x == static_cast<int64_t>(x)) {
|
||||
return Value(Value::DoubleToIntConvertibleTestNeeds, x);
|
||||
}
|
||||
|
|
@ -150,7 +155,9 @@ static Value builtinMathAtan(ExecutionState& state, Value thisValue, size_t argc
|
|||
static Value builtinMathAtan2(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
double y = argv[0].toNumber(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
double x = argv[1].toNumber(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
return Value(Value::DoubleToIntConvertibleTestNeeds, ieee754::atan2(y, x));
|
||||
}
|
||||
|
||||
|
|
@ -181,6 +188,7 @@ static Value builtinMathTrunc(ExecutionState& state, Value thisValue, size_t arg
|
|||
static Value builtinMathSign(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
double x = argv[0].toNumber(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (std::isnan(x))
|
||||
return Value(Value::NanInit);
|
||||
else if (x == 0.0) {
|
||||
|
|
@ -204,7 +212,9 @@ static Value builtinMathSqrt(ExecutionState& state, Value thisValue, size_t argc
|
|||
static Value builtinMathPow(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
double x = argv[0].toNumber(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
double y = argv[1].toNumber(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (UNLIKELY(std::isnan(y)))
|
||||
return Value(Value::NanInit);
|
||||
if (UNLIKELY(std::abs(x) == 1 && std::isinf(y)))
|
||||
|
|
@ -327,6 +337,7 @@ static Value builtinMathHypot(ExecutionState& state, Value thisValue, size_t arg
|
|||
bool has_inf = false;
|
||||
for (unsigned i = 0; i < argc; i++) {
|
||||
double value = argv[i].toNumber(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (std::isinf(value)) {
|
||||
has_inf = true;
|
||||
} else if (std::isnan(value)) {
|
||||
|
|
@ -351,6 +362,7 @@ static Value builtinMathHypot(ExecutionState& state, Value thisValue, size_t arg
|
|||
double compensation = 0;
|
||||
for (unsigned i = 0; i < argc; i++) {
|
||||
double value = argv[i].toNumber(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
double scaledArgument = value / maxValue;
|
||||
double summand = scaledArgument * scaledArgument - compensation;
|
||||
double preliminary = sum + summand;
|
||||
|
|
|
|||
|
|
@ -82,6 +82,7 @@ static Value builtinNumberConstructor(ExecutionState& state, Value thisValue, si
|
|||
} else {
|
||||
num = argv[0].toNumber(state);
|
||||
}
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
}
|
||||
|
||||
if (!newTarget.hasValue()) {
|
||||
|
|
@ -90,6 +91,7 @@ static Value builtinNumberConstructor(ExecutionState& state, Value thisValue, si
|
|||
Object* proto = Object::getPrototypeFromConstructor(state, newTarget.value(), [](ExecutionState& state, Context* constructorRealm) -> Object* {
|
||||
return constructorRealm->globalObject()->numberPrototype();
|
||||
});
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
NumberObject* numObj = new NumberObject(state, proto, num);
|
||||
return numObj;
|
||||
}
|
||||
|
|
@ -104,13 +106,14 @@ static Value builtinNumberToFixed(ExecutionState& state, Value thisValue, size_t
|
|||
} else if (thisValue.isPointerValue() && thisValue.asPointerValue()->isNumberObject()) {
|
||||
number = thisValue.asPointerValue()->asNumberObject()->primitiveValue();
|
||||
} else {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().Number.string(), true, state.context()->staticStrings().toFixed.string(), ErrorObject::Messages::GlobalObject_ThisNotNumber);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Number.string(), true, state.context()->staticStrings().toFixed.string(), ErrorObject::Messages::GlobalObject_ThisNotNumber);
|
||||
}
|
||||
|
||||
Value fractionDigits = argv[0];
|
||||
int digit = fractionDigits.toInteger(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (digit < 0 || digit > 100) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, state.context()->staticStrings().Number.string(), true, state.context()->staticStrings().toFixed.string(), ErrorObject::Messages::GlobalObject_RangeError);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::RangeError, state.context()->staticStrings().Number.string(), true, state.context()->staticStrings().toFixed.string(), ErrorObject::Messages::GlobalObject_RangeError);
|
||||
}
|
||||
|
||||
if (std::isnan(number)) {
|
||||
|
|
@ -145,11 +148,12 @@ static Value builtinNumberToExponential(ExecutionState& state, Value thisValue,
|
|||
} else if (thisValue.isPointerValue() && thisValue.asPointerValue()->isNumberObject()) {
|
||||
number = thisValue.asPointerValue()->asNumberObject()->primitiveValue();
|
||||
} else {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().Number.string(), true, state.context()->staticStrings().toExponential.string(), ErrorObject::Messages::GlobalObject_ThisNotNumber);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Number.string(), true, state.context()->staticStrings().toExponential.string(), ErrorObject::Messages::GlobalObject_ThisNotNumber);
|
||||
}
|
||||
|
||||
Value fractionDigits = argv[0];
|
||||
int digit = fractionDigits.toInteger(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
if (std::isnan(number)) { // 3
|
||||
return state.context()->staticStrings().NaN.string();
|
||||
|
|
@ -164,7 +168,7 @@ static Value builtinNumberToExponential(ExecutionState& state, Value thisValue,
|
|||
}
|
||||
|
||||
if (digit < 0 || digit > 100) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, state.context()->staticStrings().Number.string(), true, state.context()->staticStrings().toExponential.string(), ErrorObject::Messages::GlobalObject_RangeError);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::RangeError, state.context()->staticStrings().Number.string(), true, state.context()->staticStrings().toExponential.string(), ErrorObject::Messages::GlobalObject_RangeError);
|
||||
}
|
||||
|
||||
char buffer[NUMBER_TO_STRING_BUFFER_LENGTH];
|
||||
|
|
@ -187,7 +191,7 @@ static Value builtinNumberToPrecision(ExecutionState& state, Value thisValue, si
|
|||
} else if (thisValue.isPointerValue() && thisValue.asPointerValue()->isNumberObject()) {
|
||||
number = thisValue.asPointerValue()->asNumberObject()->primitiveValue();
|
||||
} else {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().Number.string(), true, state.context()->staticStrings().toPrecision.string(), ErrorObject::Messages::GlobalObject_ThisNotNumber);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Number.string(), true, state.context()->staticStrings().toPrecision.string(), ErrorObject::Messages::GlobalObject_ThisNotNumber);
|
||||
}
|
||||
|
||||
Value precision = argv[0];
|
||||
|
|
@ -196,6 +200,7 @@ static Value builtinNumberToPrecision(ExecutionState& state, Value thisValue, si
|
|||
}
|
||||
|
||||
int p = precision.toInteger(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
if (std::isnan(number)) {
|
||||
return state.context()->staticStrings().NaN.string();
|
||||
|
|
@ -210,7 +215,7 @@ static Value builtinNumberToPrecision(ExecutionState& state, Value thisValue, si
|
|||
}
|
||||
|
||||
if (p < 1 || p > 100) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, state.context()->staticStrings().Number.string(), true, state.context()->staticStrings().toPrecision.string(), ErrorObject::Messages::GlobalObject_RangeError);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::RangeError, state.context()->staticStrings().Number.string(), true, state.context()->staticStrings().toPrecision.string(), ErrorObject::Messages::GlobalObject_RangeError);
|
||||
}
|
||||
|
||||
char buffer[NUMBER_TO_STRING_BUFFER_LENGTH];
|
||||
|
|
@ -229,14 +234,15 @@ static Value builtinNumberToString(ExecutionState& state, Value thisValue, size_
|
|||
} else if (thisValue.isPointerValue() && thisValue.asPointerValue()->isNumberObject()) {
|
||||
number = thisValue.asPointerValue()->asNumberObject()->primitiveValue();
|
||||
} else {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().Number.string(), true, state.context()->staticStrings().toString.string(), ErrorObject::Messages::GlobalObject_ThisNotNumber);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Number.string(), true, state.context()->staticStrings().toString.string(), ErrorObject::Messages::GlobalObject_ThisNotNumber);
|
||||
}
|
||||
|
||||
double radix = 10;
|
||||
if (argc > 0 && !argv[0].isUndefined()) {
|
||||
radix = argv[0].toInteger(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (radix < 2 || radix > 36) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, state.context()->staticStrings().Number.string(), true, state.context()->staticStrings().toString.string(), ErrorObject::Messages::GlobalObject_RadixInvalidRange);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::RangeError, state.context()->staticStrings().Number.string(), true, state.context()->staticStrings().toString.string(), ErrorObject::Messages::GlobalObject_RadixInvalidRange);
|
||||
}
|
||||
}
|
||||
if (std::isnan(number) || std::isinf(number)) {
|
||||
|
|
@ -270,7 +276,7 @@ static Value builtinNumberToLocaleString(ExecutionState& state, Value thisValue,
|
|||
{
|
||||
RESOLVE_THIS_BINDING_TO_OBJECT(thisObject, Number, toLocaleString);
|
||||
if (!thisObject->isNumberObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ThisNotNumber);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ThisNotNumber);
|
||||
}
|
||||
|
||||
#if defined(ENABLE_ICU) && defined(ENABLE_INTL_NUMBERFORMAT)
|
||||
|
|
@ -283,7 +289,7 @@ static Value builtinNumberToLocaleString(ExecutionState& state, Value thisValue,
|
|||
} else if (thisValue.isObject() && thisValue.asObject()->isNumberObject()) {
|
||||
x = thisValue.asPointerValue()->asNumberObject()->primitiveValue();
|
||||
} else {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ThisNotNumber);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ThisNotNumber);
|
||||
}
|
||||
auto result = IntlNumberFormat::format(state, numberFormat, x);
|
||||
|
||||
|
|
@ -293,14 +299,13 @@ static Value builtinNumberToLocaleString(ExecutionState& state, Value thisValue,
|
|||
ObjectGetResult toStrFuncGetResult = thisObject->get(state, ObjectPropertyName(state.context()->staticStrings().toString));
|
||||
if (toStrFuncGetResult.hasValue()) {
|
||||
Value toStrFunc = toStrFuncGetResult.value(state, thisObject);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (toStrFunc.isCallable()) {
|
||||
// toLocaleString() ignores the first argument, unlike toString()
|
||||
return Object::call(state, toStrFunc, thisObject, 0, argv);
|
||||
}
|
||||
}
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().Number.string(), true, state.context()->staticStrings().toLocaleString.string(), ErrorObject::Messages::GlobalObject_ToLocaleStringNotCallable);
|
||||
RELEASE_ASSERT_NOT_REACHED();
|
||||
return Value();
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Number.string(), true, state.context()->staticStrings().toLocaleString.string(), ErrorObject::Messages::GlobalObject_ToLocaleStringNotCallable);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -311,9 +316,7 @@ static Value builtinNumberValueOf(ExecutionState& state, Value thisValue, size_t
|
|||
} else if (thisValue.isObject() && thisValue.asObject()->isNumberObject()) {
|
||||
return Value(Value::DoubleToIntConvertibleTestNeeds, thisValue.asPointerValue()->asNumberObject()->primitiveValue());
|
||||
}
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ThisNotNumber);
|
||||
RELEASE_ASSERT_NOT_REACHED();
|
||||
return Value();
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ThisNotNumber);
|
||||
}
|
||||
|
||||
static Value builtinNumberIsFinite(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
|
|
@ -341,6 +344,7 @@ static Value builtinNumberIsInteger(ExecutionState& state, Value thisValue, size
|
|||
}
|
||||
|
||||
double integer = argv[0].toInteger(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (number != integer) {
|
||||
return Value(Value::False);
|
||||
}
|
||||
|
|
@ -372,6 +376,7 @@ static Value builtinNumberIsSafeInteger(ExecutionState& state, Value thisValue,
|
|||
}
|
||||
|
||||
double integer = argv[0].toInteger(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (number != integer) {
|
||||
return Value(Value::False);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,19 +31,23 @@ typedef VectorWithInlineStorage<48, std::pair<ObjectPropertyName, ObjectStructur
|
|||
|
||||
static Value builtinObject__proto__Getter(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
return thisValue.toObject(state)->getPrototype(state);
|
||||
Object* obj = thisValue.toObject(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
return obj->getPrototype(state);
|
||||
}
|
||||
|
||||
static Value builtinObject__proto__Setter(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
Value value = argv[0];
|
||||
Object* thisObject = thisValue.toObject(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Setting __proto__ to a non-object, non-null value is ignored
|
||||
if (!value.isObject() && !value.isNull()) {
|
||||
return Value();
|
||||
}
|
||||
if (!thisObject->setPrototype(state, value)) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().Object.string(), false, state.context()->staticStrings().setPrototypeOf.string(), "can't set prototype of this object");
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Object.string(), false, state.context()->staticStrings().setPrototypeOf.string(), "can't set prototype of this object");
|
||||
}
|
||||
return Value();
|
||||
}
|
||||
|
|
@ -56,6 +60,7 @@ static Value builtinObjectConstructor(ExecutionState& state, Value thisValue, si
|
|||
Object* proto = Object::getPrototypeFromConstructor(state, newTarget.value(), [](ExecutionState& state, Context* constructorRealm) -> Object* {
|
||||
return constructorRealm->globalObject()->objectPrototype();
|
||||
});
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
return new Object(state, proto);
|
||||
}
|
||||
|
||||
|
|
@ -82,7 +87,8 @@ static Value builtinObjectPreventExtensions(ExecutionState& state, Value thisVal
|
|||
}
|
||||
Object* o = argv[0].asObject();
|
||||
if (!o->preventExtensions(state)) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().Object.string(), false, state.context()->staticStrings().preventExtensions.string(), "PreventExtensions is false");
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Object.string(), false, state.context()->staticStrings().preventExtensions.string(), "PreventExtensions is false");
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
|
@ -98,11 +104,14 @@ static Value builtinObjectToString(ExecutionState& state, Value thisValue, size_
|
|||
}
|
||||
|
||||
Object* thisObject = thisValue.toObject(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// check isArray first
|
||||
bool isArray = thisObject->isArray(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
Value toStringTag = thisObject->get(state, ObjectPropertyName(state.context()->vmInstance()->globalSymbols().toStringTag)).value(state, thisObject);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (toStringTag.isString()) {
|
||||
String* tag = toStringTag.asString();
|
||||
auto bad = tag->bufferAccessData();
|
||||
|
|
@ -159,13 +168,18 @@ static Value builtinObjectToString(ExecutionState& state, Value thisValue, size_
|
|||
static Value builtinObjectHasOwn(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
Object* obj = argv[0].toObject(state);
|
||||
return Value(obj->hasOwnProperty(state, ObjectPropertyName(state, argv[1])));
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
ObjectPropertyName key = ObjectPropertyName(state, argv[1]);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
return Value(obj->hasOwnProperty(state, key));
|
||||
}
|
||||
|
||||
static Value builtinObjectHasOwnProperty(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
ObjectPropertyName key(state, argv[0]);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
Object* obj = thisValue.toObject(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
return Value(obj->hasOwnProperty(state, key));
|
||||
}
|
||||
|
||||
|
|
@ -174,12 +188,13 @@ static Value objectDefineProperties(ExecutionState& state, Value object, Value p
|
|||
const StaticStrings* strings = &state.context()->staticStrings();
|
||||
|
||||
if (!object.isObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Object.string(), false, strings->defineProperty.string(), ErrorObject::Messages::GlobalObject_FirstArgumentNotObject);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, strings->Object.string(), false, strings->defineProperty.string(), ErrorObject::Messages::GlobalObject_FirstArgumentNotObject);
|
||||
}
|
||||
|
||||
Object* O = object.asObject();
|
||||
// Let props be ? ToObject(Properties).
|
||||
Object* props = properties.toObject(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// Let keys be ? props.[[OwnPropertyKeys]]().
|
||||
Object::OwnPropertyKeyVector keys = props->ownPropertyKeys(state);
|
||||
|
|
@ -189,17 +204,20 @@ static Value objectDefineProperties(ExecutionState& state, Value object, Value p
|
|||
for (size_t i = 0; i < keys.size(); i++) {
|
||||
// Let propDesc be ? props.[[GetOwnProperty]](nextKey).
|
||||
ObjectPropertyName nextKey(state, keys[i]);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
ObjectGetResult propDesc = props->getOwnProperty(state, nextKey);
|
||||
// If propDesc is not undefined and propDesc.[[Enumerable]] is true, then
|
||||
if (propDesc.hasValue() && propDesc.isEnumerable()) {
|
||||
// Let descObj be ? Get(props, nextKey).
|
||||
Value descVal = propDesc.value(state, props);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (!descVal.isObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().Object.string(), false, state.context()->staticStrings().defineProperty.string(), ErrorObject::Messages::GlobalObject_DescriptorNotObject);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Object.string(), false, state.context()->staticStrings().defineProperty.string(), ErrorObject::Messages::GlobalObject_DescriptorNotObject);
|
||||
}
|
||||
|
||||
// Let desc be ? ToPropertyDescriptor(descObj).
|
||||
ObjectPropertyDescriptor desc(state, descVal.asObject());
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Append the pair (a two element List) consisting of nextKey and desc to the end of descriptors.
|
||||
descriptors.push_back(std::make_pair(nextKey, desc));
|
||||
}
|
||||
|
|
@ -211,6 +229,7 @@ static Value objectDefineProperties(ExecutionState& state, Value object, Value p
|
|||
// Let desc be the second element of pair.
|
||||
// Perform ? DefinePropertyOrThrow(O, P, desc).
|
||||
O->defineOwnPropertyThrowsException(state, it.first, it.second);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
}
|
||||
|
||||
return O;
|
||||
|
|
@ -219,13 +238,14 @@ static Value objectDefineProperties(ExecutionState& state, Value object, Value p
|
|||
static Value builtinObjectCreate(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (!argv[0].isObject() && !argv[0].isNull())
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().Object.string(), false, state.context()->staticStrings().create.string(), ErrorObject::Messages::GlobalObject_FirstArgumentNotObjectAndNotNull);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Object.string(), false, state.context()->staticStrings().create.string(), ErrorObject::Messages::GlobalObject_FirstArgumentNotObjectAndNotNull);
|
||||
Object* obj;
|
||||
if (argv[0].isNull()) {
|
||||
obj = new Object(state, Object::PrototypeIsNull);
|
||||
} else {
|
||||
obj = new Object(state);
|
||||
obj->setPrototype(state, argv[0]);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
}
|
||||
|
||||
if (!argv[1].isUndefined())
|
||||
|
|
@ -243,21 +263,24 @@ static Value builtinObjectDefineProperty(ExecutionState& state, Value thisValue,
|
|||
// Object.defineProperty ( O, P, Attributes )
|
||||
// If Type(O) is not Object, throw a TypeError exception.
|
||||
if (!argv[0].isObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().Object.string(), false, state.context()->staticStrings().defineProperty.string(), ErrorObject::Messages::GlobalObject_FirstArgumentNotObject);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Object.string(), false, state.context()->staticStrings().defineProperty.string(), ErrorObject::Messages::GlobalObject_FirstArgumentNotObject);
|
||||
}
|
||||
Object* O = argv[0].asObject();
|
||||
|
||||
// Let key be ToPropertyKey(P).
|
||||
ObjectPropertyName key = ObjectPropertyName(state, argv[1]);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// Let desc be ToPropertyDescriptor(Attributes).
|
||||
if (!argv[2].isObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Property description must be an object");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Property description must be an object");
|
||||
}
|
||||
|
||||
ObjectPropertyDescriptor desc(state, argv[2].asObject());
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
O->defineOwnPropertyThrowsException(state, key, desc);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
return O;
|
||||
}
|
||||
|
||||
|
|
@ -277,6 +300,7 @@ static Value builtinObjectIsPrototypeOf(ExecutionState& state, Value thisValue,
|
|||
while (true) {
|
||||
// Let V be the value of the [[Prototype]] internal property of V.
|
||||
V = V.toObject(state)->getPrototype(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// if V is null, return false
|
||||
if (!V.isObject())
|
||||
return Value(false);
|
||||
|
|
@ -291,6 +315,7 @@ static Value builtinObjectPropertyIsEnumerable(ExecutionState& state, Value this
|
|||
{
|
||||
// Let P be toPropertyKey(V).
|
||||
ObjectPropertyName P(state, argv[0]);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// Let O be the result of calling ToObject passing the this value as the argument.
|
||||
RESOLVE_THIS_BINDING_TO_OBJECT(O, Object, propertyIsEnumerable);
|
||||
|
|
@ -313,12 +338,15 @@ static Value builtinObjectToLocaleString(ExecutionState& state, Value thisValue,
|
|||
// Return ? Invoke(O, "toString").
|
||||
RESOLVE_THIS_BINDING_TO_OBJECT(O, Object, toLocaleString);
|
||||
Value toString = O->get(state, ObjectPropertyName(state.context()->staticStrings().toString)).value(state, thisValue);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
return Object::call(state, toString, thisValue, 0, nullptr);
|
||||
}
|
||||
|
||||
static Value builtinObjectGetPrototypeOf(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
return argv[0].toObject(state)->getPrototype(state);
|
||||
Object* obj = argv[0].toObject(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
return obj->getPrototype(state);
|
||||
}
|
||||
|
||||
static Value builtinObjectSetPrototypeOf(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
|
|
@ -331,13 +359,13 @@ static Value builtinObjectSetPrototypeOf(ExecutionState& state, Value thisValue,
|
|||
// 1. Let O be RequireObjectCoercible(O).
|
||||
// 2. ReturnIfAbrupt(O).
|
||||
if (object.isUndefinedOrNull()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().Object.string(), false, state.context()->staticStrings().setPrototypeOf.string(), "");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Object.string(), false, state.context()->staticStrings().setPrototypeOf.string(), "");
|
||||
return Value();
|
||||
}
|
||||
|
||||
// 3. If Type(proto) is neither Object nor Null, throw a TypeError exception.
|
||||
if (!proto.isObject() && !proto.isNull()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().Object.string(), false, state.context()->staticStrings().setPrototypeOf.string(), "");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Object.string(), false, state.context()->staticStrings().setPrototypeOf.string(), "");
|
||||
return Value();
|
||||
}
|
||||
|
||||
|
|
@ -348,11 +376,13 @@ static Value builtinObjectSetPrototypeOf(ExecutionState& state, Value thisValue,
|
|||
|
||||
// 5. Let status be O.[[SetPrototypeOf]](proto).
|
||||
Object* obj = object.toObject(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
bool status = obj->setPrototype(state, proto);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// 7. If status is false, throw a TypeError exception.
|
||||
if (!status) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().Object.string(), false, state.context()->staticStrings().setPrototypeOf.string(), "can't set prototype of this object");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Object.string(), false, state.context()->staticStrings().setPrototypeOf.string(), "can't set prototype of this object");
|
||||
return Value();
|
||||
}
|
||||
|
||||
|
|
@ -371,7 +401,8 @@ static Value builtinObjectFreeze(ExecutionState& state, Value thisValue, size_t
|
|||
// Let status be ? SetIntegrityLevel(O, frozen).
|
||||
// If status is false, throw a TypeError exception.
|
||||
if (!Object::setIntegrityLevel(state, O, false)) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().Object.string(), false, state.context()->staticStrings().freeze.string(), ErrorObject::Messages::GlobalObject_IllegalFirstArgument);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Object.string(), false, state.context()->staticStrings().freeze.string(), ErrorObject::Messages::GlobalObject_IllegalFirstArgument);
|
||||
}
|
||||
|
||||
// Return O.
|
||||
|
|
@ -381,41 +412,55 @@ static Value builtinObjectFreeze(ExecutionState& state, Value thisValue, size_t
|
|||
static Value builtinObjectFromEntries(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (argv[0].isUndefinedOrNull()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().object.string(), true, state.context()->staticStrings().fromEntries.string(), ErrorObject::Messages::GlobalObject_ThisUndefinedOrNull);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().object.string(), true, state.context()->staticStrings().fromEntries.string(), ErrorObject::Messages::GlobalObject_ThisUndefinedOrNull);
|
||||
}
|
||||
Value iterable = argv[0];
|
||||
Object* obj = new Object(state);
|
||||
|
||||
auto iteratorRecord = IteratorObject::getIterator(state, iterable);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
while (true) {
|
||||
auto next = IteratorObject::iteratorStep(state, iteratorRecord);
|
||||
if (!next.hasValue()) {
|
||||
return obj;
|
||||
}
|
||||
{
|
||||
auto next = IteratorObject::iteratorStep(state, iteratorRecord);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (!next.hasValue()) {
|
||||
return obj;
|
||||
}
|
||||
|
||||
Value nextItem = IteratorObject::iteratorValue(state, next.value());
|
||||
if (!nextItem.isObject()) {
|
||||
ErrorObject* errorobj = ErrorObject::createError(state, ErrorCode::TypeError, new ASCIIString("TypeError"));
|
||||
return IteratorObject::iteratorClose(state, iteratorRecord, errorobj, true);
|
||||
}
|
||||
Value nextItem = IteratorObject::iteratorValue(state, next.value());
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (!nextItem.isObject()) {
|
||||
ErrorObject* errorobj = ErrorObject::createError(state, ErrorCode::TypeError, new ASCIIString("TypeError"));
|
||||
return IteratorObject::iteratorClose(state, iteratorRecord, errorobj, true);
|
||||
}
|
||||
|
||||
try {
|
||||
// Let k be Get(nextItem, "0").
|
||||
// If k is an abrupt completion, return ? IteratorClose(iter, k).
|
||||
Value k = nextItem.asObject()->getIndexedProperty(state, Value(0)).value(state, nextItem);
|
||||
if (state.hasPendingException())
|
||||
goto IfAbrupt;
|
||||
// Let v be Get(nextItem, "1").
|
||||
// If v is an abrupt completion, return ? IteratorClose(iter, v).
|
||||
Value v = nextItem.asObject()->getIndexedProperty(state, Value(1)).value(state, nextItem);
|
||||
if (state.hasPendingException())
|
||||
goto IfAbrupt;
|
||||
|
||||
ObjectPropertyName key(state, k);
|
||||
if (state.hasPendingException())
|
||||
goto IfAbrupt;
|
||||
obj->defineOwnPropertyThrowsException(state, key,
|
||||
ObjectPropertyDescriptor(v, ObjectPropertyDescriptor::AllPresent));
|
||||
} catch (const Value& v) {
|
||||
// we should save thrown value bdwgc cannot track thrown value
|
||||
Value exceptionValue = v;
|
||||
// If status is an abrupt completion, return ? IteratorClose(iteratorRecord, status).
|
||||
return IteratorObject::iteratorClose(state, iteratorRecord, exceptionValue, true);
|
||||
if (state.hasPendingException())
|
||||
goto IfAbrupt;
|
||||
continue;
|
||||
}
|
||||
|
||||
IfAbrupt : {
|
||||
ASSERT(state.hasPendingException());
|
||||
Value exceptionValue = state.detachPendingException();
|
||||
// If status is an abrupt completion, return ? IteratorClose(iteratorRecord, status).
|
||||
return IteratorObject::iteratorClose(state, iteratorRecord, exceptionValue, true);
|
||||
}
|
||||
}
|
||||
|
||||
return obj;
|
||||
|
|
@ -426,23 +471,29 @@ static Value builtinObjectGetOwnPropertyDescriptor(ExecutionState& state, Value
|
|||
{
|
||||
// Let obj be ToObject(O).
|
||||
Object* O = argv[0].toObject(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// Let desc be ? obj.[[GetOwnProperty]](key).
|
||||
// Return FromPropertyDescriptor(desc).
|
||||
return O->getOwnPropertyDescriptor(state, ObjectPropertyName(state, argv[1]));
|
||||
ObjectPropertyName key = ObjectPropertyName(state, argv[1]);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
return O->getOwnPropertyDescriptor(state, key);
|
||||
}
|
||||
|
||||
// https://262.ecma-international.org/#sec-object.getownpropertydescriptors
|
||||
static Value builtinObjectGetOwnPropertyDescriptors(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
Object* obj = argv[0].toObject(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
auto ownKeys = obj->ownPropertyKeys(state);
|
||||
Object* descriptors = new Object(state);
|
||||
|
||||
for (uint64_t i = 0; i < ownKeys.size(); i++) {
|
||||
Value descriptor = obj->getOwnPropertyDescriptor(state, ObjectPropertyName(state, ownKeys[i]));
|
||||
ObjectPropertyName key = ObjectPropertyName(state, ownKeys[i]);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
Value descriptor = obj->getOwnPropertyDescriptor(state, key);
|
||||
if (!descriptor.isUndefined()) {
|
||||
descriptors->defineOwnProperty(state, ObjectPropertyName(state, ownKeys[i]), ObjectPropertyDescriptor(descriptor, ObjectPropertyDescriptor::AllPresent));
|
||||
descriptors->defineOwnProperty(state, key, ObjectPropertyDescriptor(descriptor, ObjectPropertyDescriptor::AllPresent));
|
||||
}
|
||||
}
|
||||
return descriptors;
|
||||
|
|
@ -490,6 +541,7 @@ static Value builtinObjectGetOwnPropertyNames(ExecutionState& state, Value thisV
|
|||
{
|
||||
// https://www.ecma-international.org/ecma-262/6.0/#sec-object.getownpropertynames
|
||||
Object* O = argv[0].toObject(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
return getOwnPropertyKeys(state, O, GetOwnPropertyKeysType::String);
|
||||
}
|
||||
|
||||
|
|
@ -497,6 +549,7 @@ static Value builtinObjectGetOwnPropertySymbols(ExecutionState& state, Value thi
|
|||
{
|
||||
// https://www.ecma-international.org/ecma-262/6.0/#sec-object.getownpropertysymbols
|
||||
Object* O = argv[0].toObject(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
return getOwnPropertyKeys(state, O, GetOwnPropertyKeysType::Symbol);
|
||||
}
|
||||
|
||||
|
|
@ -539,7 +592,8 @@ static Value builtinObjectSeal(ExecutionState& state, Value thisValue, size_t ar
|
|||
// Let status be ? SetIntegrityLevel(O, sealed).
|
||||
// If status is false, throw a TypeError exception.
|
||||
if (!Object::setIntegrityLevel(state, O, true)) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().Object.string(), false, state.context()->staticStrings().seal.string(), ErrorObject::Messages::GlobalObject_IllegalFirstArgument);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Object.string(), false, state.context()->staticStrings().seal.string(), ErrorObject::Messages::GlobalObject_IllegalFirstArgument);
|
||||
}
|
||||
|
||||
// Return O.
|
||||
|
|
@ -551,6 +605,7 @@ static Value builtinObjectAssign(ExecutionState& state, Value thisValue, size_t
|
|||
// Object.assign ( target, ...sources )
|
||||
// Let to be ? ToObject(target).
|
||||
Object* to = argv[0].toObject(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// If only one argument was passed, return to.
|
||||
if (argc == 1) {
|
||||
return to;
|
||||
|
|
@ -565,6 +620,7 @@ static Value builtinObjectAssign(ExecutionState& state, Value thisValue, size_t
|
|||
if (!nextSource.isUndefinedOrNull()) {
|
||||
// Let from be ! ToObject(nextSource).
|
||||
from = nextSource.toObject(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Let keys be ? from.[[OwnPropertyKeys]]().
|
||||
keys = from->ownPropertyKeys(state);
|
||||
}
|
||||
|
|
@ -572,19 +628,23 @@ static Value builtinObjectAssign(ExecutionState& state, Value thisValue, size_t
|
|||
// For each element nextKey of keys in List order, do
|
||||
for (size_t i = 0; i < keys.size(); i++) {
|
||||
Value nextKey = keys[i];
|
||||
ObjectPropertyName key = ObjectPropertyName(state, nextKey);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Let desc be ? from.[[GetOwnProperty]](nextKey).
|
||||
auto desc = from->getOwnProperty(state, ObjectPropertyName(state, nextKey));
|
||||
auto desc = from->getOwnProperty(state, key);
|
||||
// If desc is not undefined and desc.[[Enumerable]] is true, then
|
||||
if (desc.hasValue() && desc.isEnumerable()) {
|
||||
// Let propValue be ? Get(from, nextKey).
|
||||
Value propValue;
|
||||
if (from->isProxyObject()) {
|
||||
propValue = from->get(state, ObjectPropertyName(state, Value(nextKey))).value(state, from);
|
||||
propValue = from->get(state, key).value(state, from);
|
||||
} else {
|
||||
propValue = desc.value(state, from);
|
||||
}
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Perform ? Set(to, nextKey, propValue, true).
|
||||
to->setThrowsException(state, ObjectPropertyName(state, nextKey), propValue, to);
|
||||
to->setThrowsException(state, key, propValue, to);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -605,6 +665,7 @@ static Value builtinObjectKeys(ExecutionState& state, Value thisValue, size_t ar
|
|||
|
||||
// Let obj be ? ToObject(O).
|
||||
Object* obj = argv[0].toObject(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Let nameList be ? EnumerableOwnProperties(obj, "key").
|
||||
auto nameList = Object::enumerableOwnProperties(state, obj, EnumerableOwnPropertiesType::Key);
|
||||
// Return CreateArrayFromList(nameList).
|
||||
|
|
@ -617,6 +678,7 @@ static Value builtinObjectValues(ExecutionState& state, Value thisValue, size_t
|
|||
|
||||
// Let obj be ? ToObject(O).
|
||||
Object* obj = argv[0].toObject(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Let nameList be ? EnumerableOwnProperties(obj, "value").
|
||||
auto nameList = Object::enumerableOwnProperties(state, obj, EnumerableOwnPropertiesType::Value);
|
||||
// Return CreateArrayFromList(nameList).
|
||||
|
|
@ -629,6 +691,7 @@ static Value builtinObjectEntries(ExecutionState& state, Value thisValue, size_t
|
|||
|
||||
// Let obj be ? ToObject(O).
|
||||
Object* obj = argv[0].toObject(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Let nameList be ? EnumerableOwnProperties(obj, "key+value").
|
||||
auto nameList = Object::enumerableOwnProperties(state, obj, EnumerableOwnPropertiesType::KeyAndValue);
|
||||
// Return CreateArrayFromList(nameList).
|
||||
|
|
@ -640,21 +703,24 @@ static Value builtinDefineGetter(ExecutionState& state, Value thisValue, size_t
|
|||
{
|
||||
// Let O be ? ToObject(this value).
|
||||
Object* O = thisValue.toObject(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// If IsCallable(getter) is false, throw a TypeError exception.
|
||||
if (!argv[1].isCallable()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, String::emptyString, true, state.context()->staticStrings().__defineGetter__.string(), ErrorObject::Messages::GlobalObject_CallbackNotCallable);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, String::emptyString, true, state.context()->staticStrings().__defineGetter__.string(), ErrorObject::Messages::GlobalObject_CallbackNotCallable);
|
||||
}
|
||||
// Let desc be PropertyDescriptor{[[Get]]: getter, [[Enumerable]]: true, [[Configurable]]: true}.
|
||||
ObjectPropertyDescriptor desc(JSGetterSetter(argv[1].asObject(), Value(Value::EmptyValue)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::EnumerablePresent | ObjectPropertyDescriptor::ConfigurablePresent));
|
||||
|
||||
// Let key be ? ToPropertyKey(P).
|
||||
ObjectPropertyName key(state, argv[0]);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// Perform ? DefinePropertyOrThrow(O, key, desc).
|
||||
#if defined(ENABLE_V8_LIKE_DEFINE_LOOKUP_GETTER_SETTER)
|
||||
O->defineOwnProperty(state, key, desc);
|
||||
#else
|
||||
O->defineOwnPropertyThrowsException(state, key, desc);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
#endif
|
||||
|
||||
// Return undefined.
|
||||
|
|
@ -666,21 +732,24 @@ static Value builtinDefineSetter(ExecutionState& state, Value thisValue, size_t
|
|||
{
|
||||
// Let O be ? ToObject(this value).
|
||||
Object* O = thisValue.toObject(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// If IsCallable(getter) is false, throw a TypeError exception.
|
||||
if (!argv[1].isCallable()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, String::emptyString, true, state.context()->staticStrings().__defineSetter__.string(), ErrorObject::Messages::GlobalObject_CallbackNotCallable);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, String::emptyString, true, state.context()->staticStrings().__defineSetter__.string(), ErrorObject::Messages::GlobalObject_CallbackNotCallable);
|
||||
}
|
||||
// Let desc be PropertyDescriptor{[[Get]]: getter, [[Enumerable]]: true, [[Configurable]]: true}.
|
||||
ObjectPropertyDescriptor desc(JSGetterSetter(Value(Value::EmptyValue), argv[1].asObject()), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::EnumerablePresent | ObjectPropertyDescriptor::ConfigurablePresent));
|
||||
|
||||
// Let key be ? ToPropertyKey(P).
|
||||
ObjectPropertyName key(state, argv[0]);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// Perform ? DefinePropertyOrThrow(O, key, desc).
|
||||
#if defined(ENABLE_V8_LIKE_DEFINE_LOOKUP_GETTER_SETTER)
|
||||
O->defineOwnProperty(state, key, desc);
|
||||
#else
|
||||
O->defineOwnPropertyThrowsException(state, key, desc);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
#endif
|
||||
|
||||
// Return undefined.
|
||||
|
|
@ -692,8 +761,10 @@ static Value builtinLookupGetter(ExecutionState& state, Value thisValue, size_t
|
|||
{
|
||||
// Let O be ? ToObject(this value).
|
||||
Object* O = thisValue.toObject(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Let key be ? ToPropertyKey(P).
|
||||
ObjectPropertyName key(state, argv[0]);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// Repeat,
|
||||
while (O) {
|
||||
|
|
@ -721,8 +792,10 @@ static Value builtinLookupSetter(ExecutionState& state, Value thisValue, size_t
|
|||
{
|
||||
// Let O be ? ToObject(this value).
|
||||
Object* O = thisValue.toObject(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Let key be ? ToPropertyKey(P).
|
||||
ObjectPropertyName key(state, argv[0]);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// Repeat,
|
||||
while (O) {
|
||||
|
|
|
|||
|
|
@ -36,19 +36,19 @@ static Value builtinPromiseConstructor(ExecutionState& state, Value thisValue, s
|
|||
{
|
||||
auto strings = &state.context()->staticStrings();
|
||||
if (!newTarget.hasValue()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Promise.string(), false, String::emptyString, "%s: Promise constructor should be called with new Promise()");
|
||||
return Value();
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, strings->Promise.string(), false, String::emptyString, "%s: Promise constructor should be called with new Promise()");
|
||||
}
|
||||
|
||||
Value executor = argv[0];
|
||||
if (!executor.isCallable()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Promise.string(), false, String::emptyString, "%s: Promise executor is not a function object");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, strings->Promise.string(), false, String::emptyString, "%s: Promise executor is not a function object");
|
||||
}
|
||||
|
||||
// Let promise be ? OrdinaryCreateFromConstructor(NewTarget, "%PromisePrototype%", « [[PromiseState]], [[PromiseResult]], [[PromiseFulfillReactions]], [[PromiseRejectReactions]], [[PromiseIsHandled]] »).
|
||||
Object* proto = Object::getPrototypeFromConstructor(state, newTarget.value(), [](ExecutionState& state, Context* constructorRealm) -> Object* {
|
||||
return constructorRealm->globalObject()->promisePrototype();
|
||||
});
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
PromiseObject* promise = new PromiseObject(state, proto);
|
||||
|
||||
PromiseReaction::Capability capability = promise->createResolvingFunctions(state);
|
||||
|
|
@ -60,12 +60,14 @@ static Value builtinPromiseConstructor(ExecutionState& state, Value thisValue, s
|
|||
state.context()->vmInstance()->triggerPromiseHook(state, VMInstance::PromiseHookType::Init, promise, (argc > 1) ? argv[1] : Value());
|
||||
}
|
||||
|
||||
try {
|
||||
{
|
||||
Value arguments[] = { capability.m_resolveFunction, capability.m_rejectFunction };
|
||||
Object::call(state, executor, Value(), 2, arguments);
|
||||
} catch (const Value& v) {
|
||||
Value thrownValue = v;
|
||||
Object::call(state, capability.m_rejectFunction, Value(), 1, &thrownValue);
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
Value thrownValue = state.detachPendingException();
|
||||
Object::call(state, capability.m_rejectFunction, Value(), 1, &thrownValue);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
}
|
||||
}
|
||||
|
||||
return promise;
|
||||
|
|
@ -77,9 +79,10 @@ static Value getPromiseResolve(ExecutionState& state, Object* promiseConstructor
|
|||
// Assert: IsConstructor(promiseConstructor) is true.
|
||||
// Let promiseResolve be ? Get(promiseConstructor, "resolve").
|
||||
auto promiseResolve = promiseConstructor->get(state, state.context()->staticStrings().resolve).value(state, promiseConstructor);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// If IsCallable(promiseResolve) is false, throw a TypeError exception.
|
||||
if (!promiseResolve.isCallable()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Promise resolve is not callable");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Promise resolve is not callable");
|
||||
}
|
||||
// Return promiseResolve.
|
||||
return promiseResolve;
|
||||
|
|
@ -93,141 +96,147 @@ static Value builtinPromiseAll(ExecutionState& state, Value thisValue, size_t ar
|
|||
// Let C be the this value.
|
||||
// If Type(C) is not Object, throw a TypeError exception.
|
||||
if (!thisValue.isObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Promise.string(), false, strings->all.string(), ErrorObject::Messages::GlobalObject_ThisNotObject);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, strings->Promise.string(), false, strings->all.string(), ErrorObject::Messages::GlobalObject_ThisNotObject);
|
||||
}
|
||||
Object* C = thisValue.asObject();
|
||||
// Let promiseCapability be NewPromiseCapability(C).
|
||||
PromiseReaction::Capability promiseCapability = PromiseObject::newPromiseCapability(state, C);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Let promiseResolve be GetPromiseResolve(C).
|
||||
Value promiseResolve;
|
||||
try {
|
||||
promiseResolve = getPromiseResolve(state, C);
|
||||
} catch (const Value& v) {
|
||||
Value thrownValue = v;
|
||||
Value promiseResolve = getPromiseResolve(state, C);
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
Value thrownValue = state.detachPendingException();
|
||||
// If value is an abrupt completion,
|
||||
// Perform ? Call(capability.[[Reject]], undefined, « value.[[Value]] »).
|
||||
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &thrownValue);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Return capability.[[Promise]].
|
||||
return promiseCapability.m_promise;
|
||||
}
|
||||
|
||||
// Let iteratorRecord be GetIterator(iterable).
|
||||
// IfAbruptRejectPromise(iteratorRecord, promiseCapability).
|
||||
IteratorRecord* iteratorRecord;
|
||||
try {
|
||||
iteratorRecord = IteratorObject::getIterator(state, argv[0]);
|
||||
} catch (const Value& v) {
|
||||
Value thrownValue = v;
|
||||
IteratorRecord* iteratorRecord = IteratorObject::getIterator(state, argv[0]);
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
Value thrownValue = state.detachPendingException();
|
||||
// If value is an abrupt completion,
|
||||
// Perform ? Call(capability.[[Reject]], undefined, « value.[[Value]] »).
|
||||
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &thrownValue);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Return capability.[[Promise]].
|
||||
return promiseCapability.m_promise;
|
||||
}
|
||||
|
||||
// Let result be PerformPromiseAll(iteratorRecord, C, promiseCapability).
|
||||
Value result;
|
||||
try {
|
||||
// Let values be a new empty List.
|
||||
ValueVector* values = new ValueVector();
|
||||
// Let remainingElementsCount be a new Record { [[value]]: 1 }.
|
||||
size_t* remainingElementsCount = new (PointerFreeGC) size_t(1);
|
||||
// Let values be a new empty List.
|
||||
ValueVector* values = new ValueVector();
|
||||
// Let remainingElementsCount be a new Record { [[value]]: 1 }.
|
||||
size_t* remainingElementsCount = new (PointerFreeGC) size_t(1);
|
||||
|
||||
// Let index be 0.
|
||||
int64_t index = 0;
|
||||
// Let index be 0.
|
||||
int64_t index = 0;
|
||||
|
||||
// Repeat
|
||||
while (true) {
|
||||
// Let next be IteratorStep(iteratorRecord).
|
||||
Optional<Object*> next;
|
||||
try {
|
||||
next = IteratorObject::iteratorStep(state, iteratorRecord);
|
||||
} catch (const Value& e) {
|
||||
// If next is an abrupt completion, set iteratorRecord.[[Done]] to true.
|
||||
iteratorRecord->m_done = true;
|
||||
// ReturnIfAbrupt(next).
|
||||
state.throwException(e);
|
||||
}
|
||||
// If next is false,
|
||||
if (!next.hasValue()) {
|
||||
// set iteratorRecord.[[done]] to true.
|
||||
iteratorRecord->m_done = true;
|
||||
// Set remainingElementsCount.[[value]] to remainingElementsCount.[[value]] − 1.
|
||||
*remainingElementsCount = *remainingElementsCount - 1;
|
||||
// If remainingElementsCount.[[value]] is 0,
|
||||
if (*remainingElementsCount == 0) {
|
||||
// Let valuesArray be CreateArrayFromList(values).
|
||||
// Perform ? Call(resultCapability.[[Resolve]], undefined, « valuesArray »).
|
||||
Value argv = Object::createArrayFromList(state, *values);
|
||||
Value resolveResult = Object::call(state, promiseCapability.m_resolveFunction, Value(), 1, &argv);
|
||||
}
|
||||
// Return resultCapability.[[Promise]].
|
||||
result = promiseCapability.m_promise;
|
||||
break;
|
||||
}
|
||||
// Let nextValue be IteratorValue(next).
|
||||
Value nextValue;
|
||||
try {
|
||||
nextValue = IteratorObject::iteratorValue(state, next.value());
|
||||
} catch (const Value& e) {
|
||||
// If next is an abrupt completion, set iteratorRecord.[[done]] to true.
|
||||
iteratorRecord->m_done = true;
|
||||
// ReturnIfAbrupt(nextValue).
|
||||
state.throwException(e);
|
||||
}
|
||||
// Append undefined to values.
|
||||
values->pushBack(Value());
|
||||
// Let nextPromise be Invoke(constructor, "resolve", « nextValue »).
|
||||
Value nextPromise = Object::call(state, promiseResolve, C, 1, &nextValue);
|
||||
|
||||
// Let resolveElement be a new built-in function object as defined in Promise.all Resolve Element Functions.
|
||||
ExtendedNativeFunctionObject* resolveElement = new ExtendedNativeFunctionObjectImpl<6>(state, NativeFunctionInfo(AtomicString(), PromiseObject::promiseAllResolveElementFunction, 1, NativeFunctionInfo::Strict));
|
||||
|
||||
// Set the [[AlreadyCalled]] internal slot of resolveElement to a new Record {[[value]]: false }.
|
||||
// Set the [[Index]] internal slot of resolveElement to index.
|
||||
// Set the [[Values]] internal slot of resolveElement to values.
|
||||
// Set the [[Capabilities]] internal slot of resolveElement to resultCapability.
|
||||
// Set the [[RemainingElements]] internal slot of resolveElement to remainingElementsCount.
|
||||
bool* alreadyCalled = new (PointerFreeGC) bool(false);
|
||||
|
||||
resolveElement->setInternalSlotAsPointer(PromiseObject::BuiltinFunctionSlot::AlreadyCalled, alreadyCalled);
|
||||
resolveElement->setInternalSlot(PromiseObject::BuiltinFunctionSlot::Index, Value(index));
|
||||
resolveElement->setInternalSlotAsPointer(PromiseObject::BuiltinFunctionSlot::Values, values);
|
||||
resolveElement->setInternalSlot(PromiseObject::BuiltinFunctionSlot::Resolve, promiseCapability.m_resolveFunction);
|
||||
resolveElement->setInternalSlot(PromiseObject::BuiltinFunctionSlot::Reject, promiseCapability.m_rejectFunction);
|
||||
resolveElement->setInternalSlotAsPointer(PromiseObject::BuiltinFunctionSlot::RemainingElements, remainingElementsCount);
|
||||
|
||||
// Set remainingElementsCount.[[value]] to remainingElementsCount.[[value]] + 1.
|
||||
*remainingElementsCount = *remainingElementsCount + 1;
|
||||
// Perform ? Invoke(nextPromise, "then", « resolveElement, resultCapability.[[Reject]] »).
|
||||
Object* nextPromiseObject = nextPromise.toObject(state);
|
||||
Value argv[] = { Value(resolveElement), Value(promiseCapability.m_rejectFunction) };
|
||||
Object::call(state, nextPromiseObject->get(state, strings->then).value(state, nextPromiseObject), nextPromiseObject, 2, argv);
|
||||
// Increase index by 1.
|
||||
index++;
|
||||
// Repeat
|
||||
while (true) {
|
||||
// Let next be IteratorStep(iteratorRecord).
|
||||
Optional<Object*> next = IteratorObject::iteratorStep(state, iteratorRecord);
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
// If next is an abrupt completion, set iteratorRecord.[[Done]] to true.
|
||||
iteratorRecord->m_done = true;
|
||||
// ReturnIfAbrupt(next).
|
||||
goto IfAbrupt;
|
||||
}
|
||||
} catch (const Value& v) {
|
||||
Value exceptionValue = v;
|
||||
// If result is an abrupt completion,
|
||||
// If iteratorRecord.[[Done]] is false, set result to IteratorClose(iteratorRecord, result).
|
||||
// IfAbruptRejectPromise(result, promiseCapability).
|
||||
try {
|
||||
if (!iteratorRecord->m_done) {
|
||||
result = IteratorObject::iteratorClose(state, iteratorRecord, exceptionValue, true);
|
||||
// If next is false,
|
||||
if (!next.hasValue()) {
|
||||
// set iteratorRecord.[[done]] to true.
|
||||
iteratorRecord->m_done = true;
|
||||
// Set remainingElementsCount.[[value]] to remainingElementsCount.[[value]] − 1.
|
||||
*remainingElementsCount = *remainingElementsCount - 1;
|
||||
// If remainingElementsCount.[[value]] is 0,
|
||||
if (*remainingElementsCount == 0) {
|
||||
// Let valuesArray be CreateArrayFromList(values).
|
||||
// Perform ? Call(resultCapability.[[Resolve]], undefined, « valuesArray »).
|
||||
Value argv = Object::createArrayFromList(state, *values);
|
||||
Value resolveResult = Object::call(state, promiseCapability.m_resolveFunction, Value(), 1, &argv);
|
||||
if (UNLIKELY(state.hasPendingException()))
|
||||
goto IfAbrupt;
|
||||
}
|
||||
} catch (const Value& v) {
|
||||
exceptionValue = v;
|
||||
// Return resultCapability.[[Promise]].
|
||||
result = promiseCapability.m_promise;
|
||||
break;
|
||||
}
|
||||
// Let nextValue be IteratorValue(next).
|
||||
Value nextValue = IteratorObject::iteratorValue(state, next.value());
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
// If next is an abrupt completion, set iteratorRecord.[[done]] to true.
|
||||
iteratorRecord->m_done = true;
|
||||
// ReturnIfAbrupt(nextValue).
|
||||
goto IfAbrupt;
|
||||
}
|
||||
// Append undefined to values.
|
||||
values->pushBack(Value());
|
||||
// Let nextPromise be Invoke(constructor, "resolve", « nextValue »).
|
||||
Value nextPromise = Object::call(state, promiseResolve, C, 1, &nextValue);
|
||||
if (UNLIKELY(state.hasPendingException()))
|
||||
goto IfAbrupt;
|
||||
|
||||
// If value is an abrupt completion,
|
||||
// Perform ? Call(capability.[[Reject]], undefined, « value.[[Value]] »).
|
||||
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &exceptionValue);
|
||||
// Return capability.[[Promise]].
|
||||
return promiseCapability.m_promise;
|
||||
// Let resolveElement be a new built-in function object as defined in Promise.all Resolve Element Functions.
|
||||
ExtendedNativeFunctionObject* resolveElement = new ExtendedNativeFunctionObjectImpl<6>(state, NativeFunctionInfo(AtomicString(), PromiseObject::promiseAllResolveElementFunction, 1, NativeFunctionInfo::Strict));
|
||||
|
||||
// Set the [[AlreadyCalled]] internal slot of resolveElement to a new Record {[[value]]: false }.
|
||||
// Set the [[Index]] internal slot of resolveElement to index.
|
||||
// Set the [[Values]] internal slot of resolveElement to values.
|
||||
// Set the [[Capabilities]] internal slot of resolveElement to resultCapability.
|
||||
// Set the [[RemainingElements]] internal slot of resolveElement to remainingElementsCount.
|
||||
bool* alreadyCalled = new (PointerFreeGC) bool(false);
|
||||
|
||||
resolveElement->setInternalSlotAsPointer(PromiseObject::BuiltinFunctionSlot::AlreadyCalled, alreadyCalled);
|
||||
resolveElement->setInternalSlot(PromiseObject::BuiltinFunctionSlot::Index, Value(index));
|
||||
resolveElement->setInternalSlotAsPointer(PromiseObject::BuiltinFunctionSlot::Values, values);
|
||||
resolveElement->setInternalSlot(PromiseObject::BuiltinFunctionSlot::Resolve, promiseCapability.m_resolveFunction);
|
||||
resolveElement->setInternalSlot(PromiseObject::BuiltinFunctionSlot::Reject, promiseCapability.m_rejectFunction);
|
||||
resolveElement->setInternalSlotAsPointer(PromiseObject::BuiltinFunctionSlot::RemainingElements, remainingElementsCount);
|
||||
|
||||
// Set remainingElementsCount.[[value]] to remainingElementsCount.[[value]] + 1.
|
||||
*remainingElementsCount = *remainingElementsCount + 1;
|
||||
// Perform ? Invoke(nextPromise, "then", « resolveElement, resultCapability.[[Reject]] »).
|
||||
Object* nextPromiseObject = nextPromise.toObject(state);
|
||||
if (UNLIKELY(state.hasPendingException()))
|
||||
goto IfAbrupt;
|
||||
Value argv[] = { Value(resolveElement), Value(promiseCapability.m_rejectFunction) };
|
||||
Value callee = nextPromiseObject->get(state, strings->then).value(state, nextPromiseObject);
|
||||
if (UNLIKELY(state.hasPendingException()))
|
||||
goto IfAbrupt;
|
||||
Object::call(state, callee, nextPromiseObject, 2, argv);
|
||||
if (UNLIKELY(state.hasPendingException()))
|
||||
goto IfAbrupt;
|
||||
// Increase index by 1.
|
||||
index++;
|
||||
}
|
||||
|
||||
// Return Completion(result).
|
||||
return result;
|
||||
|
||||
IfAbrupt:
|
||||
ASSERT(state.hasPendingException());
|
||||
Value exceptionValue = state.detachPendingException();
|
||||
// If result is an abrupt completion,
|
||||
// If iteratorRecord.[[Done]] is false, set result to IteratorClose(iteratorRecord, result).
|
||||
// IfAbruptRejectPromise(result, promiseCapability).
|
||||
if (!iteratorRecord->m_done) {
|
||||
result = IteratorObject::iteratorClose(state, iteratorRecord, exceptionValue, true);
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
exceptionValue = state.detachPendingException();
|
||||
}
|
||||
}
|
||||
|
||||
// If value is an abrupt completion,
|
||||
// Perform ? Call(capability.[[Reject]], undefined, « value.[[Value]] »).
|
||||
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &exceptionValue);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Return capability.[[Promise]].
|
||||
return promiseCapability.m_promise;
|
||||
}
|
||||
|
||||
static Value builtinPromiseRace(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
|
|
@ -237,113 +246,121 @@ static Value builtinPromiseRace(ExecutionState& state, Value thisValue, size_t a
|
|||
// Let C be the this value.
|
||||
// If Type(C) is not Object, throw a TypeError exception.
|
||||
if (!thisValue.isObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Promise.string(), false, strings->race.string(), ErrorObject::Messages::GlobalObject_ThisNotObject);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, strings->Promise.string(), false, strings->race.string(), ErrorObject::Messages::GlobalObject_ThisNotObject);
|
||||
}
|
||||
Object* C = thisValue.asObject();
|
||||
|
||||
// Let promiseCapability be NewPromiseCapability(C).
|
||||
// ReturnIfAbrupt(promiseCapability).
|
||||
PromiseReaction::Capability promiseCapability = PromiseObject::newPromiseCapability(state, C);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Let promiseResolve be GetPromiseResolve(C).
|
||||
Value resolve;
|
||||
try {
|
||||
resolve = getPromiseResolve(state, C);
|
||||
} catch (const Value& v) {
|
||||
Value thrownValue = v;
|
||||
Value resolve = getPromiseResolve(state, C);
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
Value thrownValue = state.detachPendingException();
|
||||
// If value is an abrupt completion,
|
||||
// Perform ? Call(capability.[[Reject]], undefined, « value.[[Value]] »).
|
||||
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &thrownValue);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Return capability.[[Promise]].
|
||||
return promiseCapability.m_promise;
|
||||
}
|
||||
|
||||
// Let iteratorRecord be GetIterator(iterable).
|
||||
// IfAbruptRejectPromise(iteratorRecord, promiseCapability).
|
||||
IteratorRecord* record;
|
||||
try {
|
||||
record = IteratorObject::getIterator(state, argv[0]);
|
||||
} catch (const Value& v) {
|
||||
Value thrownValue = v;
|
||||
IteratorRecord* record = IteratorObject::getIterator(state, argv[0]);
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
Value thrownValue = state.detachPendingException();
|
||||
// If value is an abrupt completion,
|
||||
// Let rejectResult be Call(capability.[[Reject]], undefined, «value.[[value]]»).
|
||||
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &thrownValue);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Return capability.[[Promise]].
|
||||
return promiseCapability.m_promise;
|
||||
}
|
||||
|
||||
// Let result be PerformPromiseRace(iteratorRecord, C, promiseCapability).
|
||||
Value result;
|
||||
try {
|
||||
// Repeat
|
||||
while (true) {
|
||||
// Let next be IteratorStep(iteratorRecord).
|
||||
Optional<Object*> next;
|
||||
try {
|
||||
next = IteratorObject::iteratorStep(state, record);
|
||||
} catch (const Value& e) {
|
||||
// If next is an abrupt completion, set iteratorRecord.[[done]] to true.
|
||||
// ReturnIfAbrupt(next).
|
||||
record->m_done = true;
|
||||
state.throwException(e);
|
||||
}
|
||||
// If next is false, then
|
||||
if (!next.hasValue()) {
|
||||
// Set iteratorRecord.[[done]] to true.
|
||||
record->m_done = true;
|
||||
// Return resultCapability.[[Promise]].
|
||||
result = promiseCapability.m_promise;
|
||||
break;
|
||||
}
|
||||
|
||||
// Let nextValue be IteratorValue(next).
|
||||
Value nextValue;
|
||||
try {
|
||||
nextValue = IteratorObject::iteratorValue(state, next.value());
|
||||
} catch (const Value& e) {
|
||||
// If next is an abrupt completion, set iteratorRecord.[[done]] to true.
|
||||
record->m_done = true;
|
||||
// ReturnIfAbrupt(next).
|
||||
state.throwException(e);
|
||||
}
|
||||
|
||||
// Let nextPromise be Invoke(C, "resolve", «nextValue»).
|
||||
Value nextPromise = Object::call(state, resolve, C, 1, &nextValue);
|
||||
// Perform ? Invoke(nextPromise, "then", « resultCapability.[[Resolve]], resultCapability.[[Reject]] »).
|
||||
Object* nextPromiseObject = nextPromise.toObject(state);
|
||||
Value argv[] = { Value(promiseCapability.m_resolveFunction), Value(promiseCapability.m_rejectFunction) };
|
||||
Object::call(state, nextPromiseObject->get(state, strings->then).value(state, nextPromiseObject), nextPromiseObject, 2, argv);
|
||||
// Repeat
|
||||
while (true) {
|
||||
// Let next be IteratorStep(iteratorRecord).
|
||||
Optional<Object*> next = IteratorObject::iteratorStep(state, record);
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
// If next is an abrupt completion, set iteratorRecord.[[done]] to true.
|
||||
// ReturnIfAbrupt(next).
|
||||
record->m_done = true;
|
||||
goto IfAbrupt;
|
||||
}
|
||||
} catch (const Value& e) {
|
||||
Value exceptionValue = e;
|
||||
// If result is an abrupt completion, then
|
||||
// If iteratorRecord.[[Done]] is false, set result to IteratorClose(iteratorRecord, result).
|
||||
// IfAbruptRejectPromise(result, promiseCapability).
|
||||
try {
|
||||
if (!record->m_done) {
|
||||
result = IteratorObject::iteratorClose(state, record, exceptionValue, true);
|
||||
}
|
||||
} catch (const Value& v) {
|
||||
exceptionValue = v;
|
||||
// If next is false, then
|
||||
if (!next.hasValue()) {
|
||||
// Set iteratorRecord.[[done]] to true.
|
||||
record->m_done = true;
|
||||
// Return resultCapability.[[Promise]].
|
||||
result = promiseCapability.m_promise;
|
||||
break;
|
||||
}
|
||||
// If value is an abrupt completion,
|
||||
// Perform ? Call(capability.[[Reject]], undefined, « value.[[Value]] »).
|
||||
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &exceptionValue);
|
||||
// Return capability.[[Promise]].
|
||||
return promiseCapability.m_promise;
|
||||
|
||||
// Let nextValue be IteratorValue(next).
|
||||
Value nextValue = IteratorObject::iteratorValue(state, next.value());
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
// If next is an abrupt completion, set iteratorRecord.[[done]] to true.
|
||||
record->m_done = true;
|
||||
// ReturnIfAbrupt(next).
|
||||
goto IfAbrupt;
|
||||
}
|
||||
|
||||
// Let nextPromise be Invoke(C, "resolve", «nextValue»).
|
||||
Value nextPromise = Object::call(state, resolve, C, 1, &nextValue);
|
||||
if (UNLIKELY(state.hasPendingException()))
|
||||
goto IfAbrupt;
|
||||
|
||||
// Perform ? Invoke(nextPromise, "then", « resultCapability.[[Resolve]], resultCapability.[[Reject]] »).
|
||||
Object* nextPromiseObject = nextPromise.toObject(state);
|
||||
if (UNLIKELY(state.hasPendingException()))
|
||||
goto IfAbrupt;
|
||||
Value argv[] = { Value(promiseCapability.m_resolveFunction), Value(promiseCapability.m_rejectFunction) };
|
||||
Value callee = nextPromiseObject->get(state, strings->then).value(state, nextPromiseObject);
|
||||
if (UNLIKELY(state.hasPendingException()))
|
||||
goto IfAbrupt;
|
||||
Object::call(state, callee, nextPromiseObject, 2, argv);
|
||||
if (UNLIKELY(state.hasPendingException()))
|
||||
goto IfAbrupt;
|
||||
}
|
||||
|
||||
// Return Completion(result).
|
||||
return result;
|
||||
|
||||
IfAbrupt:
|
||||
ASSERT(state.hasPendingException());
|
||||
Value exceptionValue = state.detachPendingException();
|
||||
// If result is an abrupt completion, then
|
||||
// If iteratorRecord.[[Done]] is false, set result to IteratorClose(iteratorRecord, result).
|
||||
// IfAbruptRejectPromise(result, promiseCapability).
|
||||
if (!record->m_done) {
|
||||
result = IteratorObject::iteratorClose(state, record, exceptionValue, true);
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
exceptionValue = state.detachPendingException();
|
||||
}
|
||||
}
|
||||
// If value is an abrupt completion,
|
||||
// Perform ? Call(capability.[[Reject]], undefined, « value.[[Value]] »).
|
||||
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &exceptionValue);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Return capability.[[Promise]].
|
||||
return promiseCapability.m_promise;
|
||||
}
|
||||
|
||||
static Value builtinPromiseReject(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
auto strings = &state.context()->staticStrings();
|
||||
Object* thisObject = thisValue.toObject(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
PromiseReaction::Capability capability = PromiseObject::newPromiseCapability(state, thisObject);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
Value arguments[] = { argv[0] };
|
||||
Object::call(state, capability.m_rejectFunction, Value(), 1, arguments);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
return capability.m_promise;
|
||||
}
|
||||
|
||||
|
|
@ -354,7 +371,7 @@ static Value builtinPromiseResolve(ExecutionState& state, Value thisValue, size_
|
|||
const Value& C = thisValue;
|
||||
// If Type(C) is not Object, throw a TypeError exception.
|
||||
if (!C.isObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().Promise.string(), false, state.context()->staticStrings().resolve.string(), "%s: PromiseResolve called on non-object");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Promise.string(), false, state.context()->staticStrings().resolve.string(), "%s: PromiseResolve called on non-object");
|
||||
}
|
||||
// Return ? PromiseResolve(C, x).
|
||||
return PromiseObject::promiseResolve(state, C.asObject(), argv[0]);
|
||||
|
|
@ -364,8 +381,10 @@ static Value builtinPromiseCatch(ExecutionState& state, Value thisValue, size_t
|
|||
{
|
||||
auto strings = &state.context()->staticStrings();
|
||||
Object* thisObject = thisValue.toObject(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
Value onRejected = argv[0];
|
||||
Value then = thisObject->get(state, strings->then).value(state, thisObject);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
Value arguments[] = { Value(), onRejected };
|
||||
return Object::call(state, then, thisObject, 2, arguments);
|
||||
}
|
||||
|
|
@ -377,11 +396,12 @@ static Value builtinPromiseFinally(ExecutionState& state, Value thisValue, size_
|
|||
auto strings = &state.context()->staticStrings();
|
||||
|
||||
if (!thisValue.isObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Promise.string(), false, strings->finally.string(), "%s: not a Promise object");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, strings->Promise.string(), false, strings->finally.string(), "%s: not a Promise object");
|
||||
}
|
||||
|
||||
Object* thisObject = thisValue.asObject();
|
||||
Value C = thisObject->speciesConstructor(state, state.context()->globalObject()->promise());
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
Value onFinally = argv[0];
|
||||
Value arguments[] = { onFinally, onFinally };
|
||||
|
|
@ -400,16 +420,20 @@ static Value builtinPromiseFinally(ExecutionState& state, Value thisValue, size_
|
|||
}
|
||||
|
||||
Value then = thisObject->get(state, strings->then).value(state, thisObject);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
return Object::call(state, then, thisObject, 2, arguments);
|
||||
}
|
||||
|
||||
static Value builtinPromiseThen(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
auto strings = &state.context()->staticStrings();
|
||||
if (!thisValue.isObject() || !thisValue.asObject()->isPromiseObject())
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Promise.string(), false, strings->then.string(), "%s: not a Promise object");
|
||||
if (!thisValue.isObject() || !thisValue.asObject()->isPromiseObject()) {
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, strings->Promise.string(), false, strings->then.string(), "%s: not a Promise object");
|
||||
}
|
||||
Value C = thisValue.asObject()->speciesConstructor(state, state.context()->globalObject()->promise());
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
PromiseReaction::Capability promiseCapability = PromiseObject::newPromiseCapability(state, C.asObject(), thisValue.asObject()->asPromiseObject());
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
return thisValue.asObject()->asPromiseObject()->then(state, argv[0], argv[1], promiseCapability).value();
|
||||
}
|
||||
|
||||
|
|
@ -428,14 +452,12 @@ static Value performPromiseAllSettled(ExecutionState& state, IteratorRecord* ite
|
|||
// Repeat,
|
||||
while (true) {
|
||||
// Let next be IteratorStep(iteratorRecord).
|
||||
Optional<Object*> next;
|
||||
try {
|
||||
next = IteratorObject::iteratorStep(state, iteratorRecord);
|
||||
} catch (const Value& e) {
|
||||
Optional<Object*> next = IteratorObject::iteratorStep(state, iteratorRecord);
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
// If next is an abrupt completion, set iteratorRecord.[[Done]] to true.
|
||||
iteratorRecord->m_done = true;
|
||||
// ReturnIfAbrupt(next).
|
||||
state.throwException(e);
|
||||
return Value(Value::Exception);
|
||||
}
|
||||
|
||||
// If next is false, then
|
||||
|
|
@ -450,20 +472,19 @@ static Value performPromiseAllSettled(ExecutionState& state, IteratorRecord* ite
|
|||
Value valuesArray = ArrayObject::createArrayFromList(state, *values);
|
||||
// Perform ? Call(resultCapability.[[Resolve]], undefined, « valuesArray »).
|
||||
Object::call(state, resultCapability.m_resolveFunction, Value(), 1, &valuesArray);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
}
|
||||
// Return resultCapability.[[Promise]].
|
||||
return resultCapability.m_promise;
|
||||
}
|
||||
|
||||
// Let nextValue be IteratorValue(next).
|
||||
Value nextValue;
|
||||
try {
|
||||
nextValue = IteratorObject::iteratorValue(state, next.value());
|
||||
} catch (const Value& e) {
|
||||
Value nextValue = IteratorObject::iteratorValue(state, next.value());
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
// If nextValue is an abrupt completion, set iteratorRecord.[[Done]] to true.
|
||||
iteratorRecord->m_done = true;
|
||||
// ReturnIfAbrupt(nextValue).
|
||||
state.throwException(e);
|
||||
return Value(Value::Exception);
|
||||
}
|
||||
|
||||
// Append undefined to values.
|
||||
|
|
@ -471,6 +492,7 @@ static Value performPromiseAllSettled(ExecutionState& state, IteratorRecord* ite
|
|||
// Let nextPromise be ? Call(promiseResolve, constructor, « nextValue »).
|
||||
Value nextValueArgv = nextValue;
|
||||
Value nextPromise = Object::call(state, promiseResolve, constructor, 1, &nextValueArgv);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Let steps be the algorithm steps defined in Promise.allSettled Resolve Element Functions.
|
||||
// Let resolveElement be ! CreateBuiltinFunction(steps, « [[AlreadyCalled]], [[Index]], [[Values]], [[Capability]], [[RemainingElements]] »).
|
||||
// Let alreadyCalled be the Record { [[Value]]: false }.
|
||||
|
|
@ -507,7 +529,10 @@ static Value performPromiseAllSettled(ExecutionState& state, IteratorRecord* ite
|
|||
*remainingElementsCount = *remainingElementsCount + 1;
|
||||
// Perform ? Invoke(nextPromise, "then", « resolveElement, rejectElement »).
|
||||
Value argv[2] = { resolveElement, rejectElement };
|
||||
Object::call(state, Object::getMethod(state, nextPromise, state.context()->staticStrings().then), nextPromise, 2, argv);
|
||||
Value callee = Object::getMethod(state, nextPromise, state.context()->staticStrings().then);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
Object::call(state, callee, nextPromise, 2, argv);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Set index to index + 1.
|
||||
index++;
|
||||
}
|
||||
|
|
@ -521,66 +546,58 @@ static Value builtinPromiseAllSettled(ExecutionState& state, Value thisValue, si
|
|||
// Let C be the this value.
|
||||
// If Type(C) is not Object, throw a TypeError exception.
|
||||
if (!thisValue.isObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "this value of allSettled is not Object");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "this value of allSettled is not Object");
|
||||
}
|
||||
Object* C = thisValue.asObject();
|
||||
// Let promiseCapability be ? NewPromiseCapability(C).
|
||||
auto promiseCapability = PromiseObject::newPromiseCapability(state, C);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Let promiseResolve be GetPromiseResolve(C).
|
||||
Value promiseResolve;
|
||||
try {
|
||||
promiseResolve = getPromiseResolve(state, C);
|
||||
} catch (const Value& v) {
|
||||
Value thrownValue = v;
|
||||
Value promiseResolve = getPromiseResolve(state, C);
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
Value thrownValue = state.detachPendingException();
|
||||
// If value is an abrupt completion,
|
||||
// Perform ? Call(capability.[[Reject]], undefined, « value.[[Value]] »).
|
||||
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &thrownValue);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Return capability.[[Promise]].
|
||||
return promiseCapability.m_promise;
|
||||
}
|
||||
|
||||
// Let iteratorRecord be GetIterator(iterable).
|
||||
// IfAbruptRejectPromise(iteratorRecord, promiseCapability).
|
||||
IteratorRecord* iteratorRecord;
|
||||
try {
|
||||
iteratorRecord = IteratorObject::getIterator(state, argv[0]);
|
||||
} catch (const Value& v) {
|
||||
Value thrownValue = v;
|
||||
IteratorRecord* iteratorRecord = IteratorObject::getIterator(state, argv[0]);
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
Value thrownValue = state.detachPendingException();
|
||||
// If value is an abrupt completion,
|
||||
// Perform ? Call(capability.[[Reject]], undefined, « value.[[Value]] »).
|
||||
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &thrownValue);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Return capability.[[Promise]].
|
||||
return promiseCapability.m_promise;
|
||||
}
|
||||
|
||||
Value result;
|
||||
// Let result be PerformPromiseAllSettled(iteratorRecord, C, promiseCapability).
|
||||
try {
|
||||
result = performPromiseAllSettled(state, iteratorRecord, C, promiseCapability, promiseResolve);
|
||||
} catch (const Value& v) {
|
||||
Value exceptionValue = v;
|
||||
Value result = performPromiseAllSettled(state, iteratorRecord, C, promiseCapability, promiseResolve);
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
Value exceptionValue = state.detachPendingException();
|
||||
// If result is an abrupt completion,
|
||||
// If iteratorRecord.[[Done]] is false, set result to IteratorClose(iteratorRecord, result).
|
||||
if (!iteratorRecord->m_done) {
|
||||
try {
|
||||
result = IteratorObject::iteratorClose(state, iteratorRecord, exceptionValue, true);
|
||||
} catch (const Value& v) {
|
||||
exceptionValue = v;
|
||||
// IfAbruptRejectPromise(result, promiseCapability).
|
||||
// If value is an abrupt completion,
|
||||
// Perform ? Call(capability.[[Reject]], undefined, « value.[[Value]] »).
|
||||
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &exceptionValue);
|
||||
// Return capability.[[Promise]].
|
||||
return promiseCapability.m_promise;
|
||||
result = IteratorObject::iteratorClose(state, iteratorRecord, exceptionValue, true);
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
exceptionValue = state.detachPendingException();
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
} else {
|
||||
// IfAbruptRejectPromise(result, promiseCapability).
|
||||
// If value is an abrupt completion,
|
||||
// Perform ? Call(capability.[[Reject]], undefined, « value.[[Value]] »).
|
||||
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &exceptionValue);
|
||||
// Return capability.[[Promise]].
|
||||
return promiseCapability.m_promise;
|
||||
}
|
||||
// IfAbruptRejectPromise(result, promiseCapability).
|
||||
// If value is an abrupt completion,
|
||||
// Perform ? Call(capability.[[Reject]], undefined, « value.[[Value]] »).
|
||||
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &exceptionValue);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Return capability.[[Promise]].
|
||||
return promiseCapability.m_promise;
|
||||
}
|
||||
// Return Completion(result).
|
||||
return result;
|
||||
|
|
@ -603,12 +620,10 @@ static Value performPromiseAny(ExecutionState& state, IteratorRecord* iteratorRe
|
|||
// Let next be IteratorStep(iteratorRecord).
|
||||
// If next is an abrupt completion, set iteratorRecord.[[Done]] to true.
|
||||
// ReturnIfAbrupt(next).
|
||||
Optional<Object*> next;
|
||||
try {
|
||||
next = IteratorObject::iteratorStep(state, iteratorRecord);
|
||||
} catch (const Value& v) {
|
||||
Optional<Object*> next = IteratorObject::iteratorStep(state, iteratorRecord);
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
iteratorRecord->m_done = true;
|
||||
state.throwException(v);
|
||||
return Value(Value::Exception);
|
||||
}
|
||||
|
||||
// If next is false, then
|
||||
|
|
@ -625,28 +640,28 @@ static Value performPromiseAny(ExecutionState& state, IteratorRecord* iteratorRe
|
|||
error->defineOwnPropertyThrowsException(state, ObjectPropertyName(state, String::fromASCII("errors")),
|
||||
ObjectPropertyDescriptor(Object::createArrayFromList(state, *errors),
|
||||
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::ConfigurablePresent | ObjectPropertyDescriptor::WritablePresent)));
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Return ThrowCompletion(error).
|
||||
state.throwException(error);
|
||||
THROW_EXCEPTION_RETURN_VALUE(state, error);
|
||||
}
|
||||
// Return resultCapability.[[Promise]].
|
||||
return resultCapability.m_promise;
|
||||
}
|
||||
|
||||
// Let nextValue be IteratorValue(next).
|
||||
Value nextValue;
|
||||
try {
|
||||
nextValue = IteratorObject::iteratorValue(state, next.value());
|
||||
} catch (const Value& v) {
|
||||
Value nextValue = IteratorObject::iteratorValue(state, next.value());
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
// If nextValue is an abrupt completion, set iteratorRecord.[[Done]] to true.
|
||||
iteratorRecord->m_done = true;
|
||||
// ReturnIfAbrupt(nextValue).
|
||||
state.throwException(v);
|
||||
return Value(Value::Exception);
|
||||
}
|
||||
// Append undefined to errors.
|
||||
errors->pushBack(Value());
|
||||
// Let nextPromise be ? Call(promiseResolve, constructor, « nextValue »).
|
||||
Value argv = nextValue;
|
||||
Value nextPromise = Object::call(state, promiseResolve, constructor, 1, &argv);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Let steps be the algorithm steps defined in Promise.any Reject Element Functions.
|
||||
// Let rejectElement be ! CreateBuiltinFunction(steps, « [[AlreadyCalled]], [[Index]], [[Errors]], [[Capability]], [[RemainingElements]] »).
|
||||
ExtendedNativeFunctionObject* rejectElement = new ExtendedNativeFunctionObjectImpl<6>(state, NativeFunctionInfo(AtomicString(), PromiseObject::promiseAnyRejectElementFunction, 1, NativeFunctionInfo::Strict));
|
||||
|
|
@ -667,8 +682,12 @@ static Value performPromiseAny(ExecutionState& state, IteratorRecord* iteratorRe
|
|||
|
||||
// Perform ? Invoke(nextPromise, "then", « resultCapability.[[Resolve]], rejectElement »).
|
||||
Object* nextPromiseObject = nextPromise.toObject(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
Value argv2[] = { Value(resultCapability.m_resolveFunction), Value(rejectElement) };
|
||||
Object::call(state, nextPromiseObject->get(state, strings->then).value(state, nextPromiseObject), nextPromiseObject, 2, argv2);
|
||||
Value callee = nextPromiseObject->get(state, strings->then).value(state, nextPromiseObject);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
Object::call(state, callee, nextPromiseObject, 2, argv2);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Set index to index + 1.
|
||||
index++;
|
||||
}
|
||||
|
|
@ -683,22 +702,22 @@ static Value builtinPromiseAny(ExecutionState& state, Value thisValue, size_t ar
|
|||
// Let C be the this value.
|
||||
// If Type(C) is not Object, throw a TypeError exception.
|
||||
if (!thisValue.isObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Promise.string(), false, strings->all.string(), ErrorObject::Messages::GlobalObject_ThisNotObject);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, strings->Promise.string(), false, strings->all.string(), ErrorObject::Messages::GlobalObject_ThisNotObject);
|
||||
}
|
||||
Object* C = thisValue.asObject();
|
||||
|
||||
// Let promiseCapability be NewPromiseCapability(C).
|
||||
PromiseReaction::Capability promiseCapability = PromiseObject::newPromiseCapability(state, C);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Let promiseResolve be GetPromiseResolve(C).
|
||||
// IfAbruptRejectPromise(promiseResolve, promiseCapability).
|
||||
Value promiseResolve;
|
||||
try {
|
||||
promiseResolve = getPromiseResolve(state, C);
|
||||
} catch (const Value& v) {
|
||||
Value thrownValue = v;
|
||||
Value promiseResolve = getPromiseResolve(state, C);
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
Value thrownValue = state.detachPendingException();
|
||||
// If value is an abrupt completion,
|
||||
// Perform ? Call(capability.[[Reject]], undefined, « value.[[Value]] »).
|
||||
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &thrownValue);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Return capability.[[Promise]].
|
||||
return promiseCapability.m_promise;
|
||||
}
|
||||
|
|
@ -706,35 +725,32 @@ static Value builtinPromiseAny(ExecutionState& state, Value thisValue, size_t ar
|
|||
// Let iteratorRecord be GetIterator(iterable).
|
||||
// IfAbruptRejectPromise(iteratorRecord, promiseCapability).
|
||||
const Value& iterable = argv[0];
|
||||
IteratorRecord* iteratorRecord = nullptr;
|
||||
try {
|
||||
iteratorRecord = IteratorObject::getIterator(state, iterable);
|
||||
} catch (const Value& v) {
|
||||
Value thrownValue = v;
|
||||
IteratorRecord* iteratorRecord = IteratorObject::getIterator(state, iterable);
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
Value thrownValue = state.detachPendingException();
|
||||
// If value is an abrupt completion,
|
||||
// Perform ? Call(capability.[[Reject]], undefined, « value.[[Value]] »).
|
||||
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &thrownValue);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Return capability.[[Promise]].
|
||||
return promiseCapability.m_promise;
|
||||
}
|
||||
|
||||
// Let result be PerformPromiseAny(iteratorRecord, C, promiseCapability, promiseResolve).
|
||||
Value result;
|
||||
try {
|
||||
result = performPromiseAny(state, iteratorRecord, C, promiseCapability, promiseResolve);
|
||||
} catch (const Value& v) {
|
||||
Value thrownValue = v;
|
||||
Value result = performPromiseAny(state, iteratorRecord, C, promiseCapability, promiseResolve);
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
Value thrownValue = state.detachPendingException();
|
||||
// If result is an abrupt completion, then
|
||||
// If iteratorRecord.[[Done]] is false, set result to IteratorClose(iteratorRecord, result).
|
||||
try {
|
||||
if (!iteratorRecord->m_done) {
|
||||
IteratorObject::iteratorClose(state, iteratorRecord, thrownValue, true);
|
||||
if (!iteratorRecord->m_done) {
|
||||
IteratorObject::iteratorClose(state, iteratorRecord, thrownValue, true);
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
thrownValue = state.detachPendingException();
|
||||
}
|
||||
} catch (const Value& v) {
|
||||
thrownValue = v;
|
||||
}
|
||||
// IfAbruptRejectPromise(result, promiseCapability).
|
||||
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &thrownValue);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
return promiseCapability.m_promise;
|
||||
}
|
||||
// Return Completion(result).
|
||||
|
|
|
|||
|
|
@ -33,14 +33,16 @@ static Value builtinProxyConstructor(ExecutionState& state, Value thisValue, siz
|
|||
auto strings = &state.context()->staticStrings();
|
||||
|
||||
if (!newTarget.hasValue()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString, "%s: calling a builtin Proxy constructor without new is forbidden");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString, "%s: calling a builtin Proxy constructor without new is forbidden");
|
||||
return Value();
|
||||
}
|
||||
|
||||
Value target = argv[0];
|
||||
Value handler = argv[1];
|
||||
|
||||
return ProxyObject::createProxy(state, target, handler);
|
||||
ProxyObject* result = ProxyObject::createProxy(state, target, handler);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
return result;
|
||||
}
|
||||
|
||||
// https://www.ecma-international.org/ecma-262/6.0/#sec-proxy-revocation-functions
|
||||
|
|
@ -84,6 +86,7 @@ static Value builtinProxyRevocable(ExecutionState& state, Value thisValue, size_
|
|||
|
||||
// 1. Let p be ProxyCreate(target, handler).
|
||||
Value proxy = ProxyObject::createProxy(state, target, handler);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// 3. Let revoker be a new built-in function object as defined in 26.2.2.1.1.
|
||||
// 4. Set the [[RevocableProxy]] internal slot of revoker to p.
|
||||
|
|
@ -96,10 +99,12 @@ static Value builtinProxyRevocable(ExecutionState& state, Value thisValue, size_
|
|||
// 6. Perform CreateDataProperty(result, "proxy", p).
|
||||
result->defineOwnPropertyThrowsException(state, ObjectPropertyName(strings->proxy),
|
||||
ObjectPropertyDescriptor(proxy, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// 7. Perform CreateDataProperty(result, "revoke", revoker).
|
||||
result->defineOwnPropertyThrowsException(state, ObjectPropertyName(strings->revoke),
|
||||
ObjectPropertyDescriptor(revoker, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// 8. Return result.
|
||||
return result;
|
||||
|
|
|
|||
|
|
@ -39,11 +39,12 @@ static Value builtinReflectApply(ExecutionState& state, Value thisValue, size_t
|
|||
|
||||
// 1. If IsCallable(target) is false, throw a TypeError exception.
|
||||
if (!target.isObject() || !target.asObject()->isCallable()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Reflect.string(), false, String::emptyString, "%s: calling a not-callable target in apply function is forbidden");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, strings->Reflect.string(), false, String::emptyString, "%s: calling a not-callable target in apply function is forbidden");
|
||||
}
|
||||
|
||||
// 2. Let args be CreateListFromArrayLike(argumentsList).
|
||||
auto args = Object::createListFromArrayLike(state, argList);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// 5. Return Call(target, thisArgument, args).
|
||||
return Object::call(state, target, thisArgument, args.size(), args.data());
|
||||
|
|
@ -59,17 +60,18 @@ static Value builtinReflectConstruct(ExecutionState& state, Value thisValue, siz
|
|||
|
||||
// 1. If IsConstructor(target) is false, throw a TypeError exception.
|
||||
if (!target.isConstructor()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Reflect.string(), false, String::emptyString, "%s: The target of Reflect.construct should has a construct method");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, strings->Reflect.string(), false, String::emptyString, "%s: The target of Reflect.construct should has a construct method");
|
||||
}
|
||||
|
||||
// 2. If newTarget is not present, let newTarget be target.
|
||||
// 3. Else, if IsConstructor(newTarget) is false, throw a TypeError exception.
|
||||
if (!newTargetArg.isConstructor()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Reflect.string(), false, String::emptyString, "%s: The new target of Reflect.construct should be a constructor");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, strings->Reflect.string(), false, String::emptyString, "%s: The new target of Reflect.construct should be a constructor");
|
||||
}
|
||||
|
||||
// 4. Let args be CreateListFromArrayLike(argumentsList).
|
||||
auto args = Object::createListFromArrayLike(state, argList);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// 6. Return Construct(target, args, newTarget).
|
||||
return Object::construct(state, target, args.size(), args.data(), newTargetArg.asObject());
|
||||
}
|
||||
|
|
@ -82,17 +84,21 @@ static Value builtinReflectDefineProperty(ExecutionState& state, Value thisValue
|
|||
|
||||
// 1. If Type(target) is not Object, throw a TypeError exception.
|
||||
if (!target.isObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Reflect.string(), false, String::emptyString, "%s: The target of Reflect.defineProperty should be an Object");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, strings->Reflect.string(), false, String::emptyString, "%s: The target of Reflect.defineProperty should be an Object");
|
||||
}
|
||||
|
||||
// 2. Let key be ToPropertyKey(propertyKey).
|
||||
ObjectPropertyName key(state, argv[1]);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// 3. Let desc be ToPropertyDescriptor(attributes).
|
||||
ObjectPropertyDescriptor desc(state, argv[2].asObject());
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// 6. Return target.[[DefineOwnProperty]](key, desc).
|
||||
return Value(target.asObject()->defineOwnProperty(state, key, desc));
|
||||
bool result = target.asObject()->defineOwnProperty(state, key, desc);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
return Value(result);
|
||||
}
|
||||
|
||||
// https://www.ecma-international.org/ecma-262/6.0/#sec-reflect.deleteproperty
|
||||
|
|
@ -103,14 +109,17 @@ static Value builtinReflectDeleteProperty(ExecutionState& state, Value thisValue
|
|||
|
||||
// 1. If Type(target) is not Object, throw a TypeError exception.
|
||||
if (!target.isObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Reflect.string(), false, String::emptyString, "%s: The target of Reflect.deleteProperty should be an Object");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, strings->Reflect.string(), false, String::emptyString, "%s: The target of Reflect.deleteProperty should be an Object");
|
||||
}
|
||||
|
||||
// 2. Let key be ToPropertyKey(propertyKey).
|
||||
ObjectPropertyName key(state, argv[1]);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// 4. Return target.[[Delete]](key).
|
||||
return Value(target.asObject()->deleteOwnProperty(state, key));
|
||||
bool result = target.asObject()->deleteOwnProperty(state, key);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
return Value(result);
|
||||
}
|
||||
|
||||
// https://www.ecma-international.org/ecma-262/6.0/#sec-reflect.get
|
||||
|
|
@ -121,11 +130,12 @@ static Value builtinReflectGet(ExecutionState& state, Value thisValue, size_t ar
|
|||
|
||||
// 1. If Type(target) is not Object, throw a TypeError exception.
|
||||
if (!target.isObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Reflect.string(), false, String::emptyString, "%s: The target of Reflect.get should be an Object");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, strings->Reflect.string(), false, String::emptyString, "%s: The target of Reflect.get should be an Object");
|
||||
}
|
||||
|
||||
// 2. Let key be ToPropertyKey(propertyKey).
|
||||
ObjectPropertyName key(state, argv[1]);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// 4. If receiver is not present, then
|
||||
// 4.a. Let receiver be target.
|
||||
|
|
@ -143,11 +153,12 @@ static Value builtinReflectGetOwnPropertyDescriptor(ExecutionState& state, Value
|
|||
|
||||
// 1. If Type(target) is not Object, throw a TypeError exception.
|
||||
if (!target.isObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Reflect.string(), false, String::emptyString, "%s: The target of Reflect.getOwnPropertyDescriptor should be an Object");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, strings->Reflect.string(), false, String::emptyString, "%s: The target of Reflect.getOwnPropertyDescriptor should be an Object");
|
||||
}
|
||||
|
||||
// 2. Let key be ToPropertyKey(propertyKey).
|
||||
ObjectPropertyName key(state, argv[1]);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// 4. Let desc be target.[[GetOwnProperty]](key).
|
||||
ObjectGetResult desc = target.asObject()->getOwnProperty(state, key);
|
||||
|
|
@ -164,7 +175,7 @@ static Value builtinReflectGetPrototypeOf(ExecutionState& state, Value thisValue
|
|||
|
||||
// 1. If Type(target) is not Object, throw a TypeError exception.
|
||||
if (!target.isObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Reflect.string(), false, String::emptyString, "%s: The target of Reflect.getPrototypeOf should be an Object");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, strings->Reflect.string(), false, String::emptyString, "%s: The target of Reflect.getPrototypeOf should be an Object");
|
||||
}
|
||||
|
||||
// 2. Return target.[[GetPrototypeOf]]().
|
||||
|
|
@ -179,14 +190,17 @@ static Value builtinReflectHas(ExecutionState& state, Value thisValue, size_t ar
|
|||
|
||||
// 1. If Type(target) is not Object, throw a TypeError exception.
|
||||
if (!target.isObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Reflect.string(), false, String::emptyString, "%s: The target of Reflect.has should be an Object");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, strings->Reflect.string(), false, String::emptyString, "%s: The target of Reflect.has should be an Object");
|
||||
}
|
||||
|
||||
// 2. Let key be ToPropertyKey(propertyKey).
|
||||
ObjectPropertyName key(state, argv[1]);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// 4. Return target.[[HasProperty]](key).
|
||||
return Value(target.asObject()->hasProperty(state, key));
|
||||
auto result = target.asObject()->hasProperty(state, key);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
return Value(result);
|
||||
}
|
||||
|
||||
// https://www.ecma-international.org/ecma-262/6.0/#sec-reflect.isextensible
|
||||
|
|
@ -197,11 +211,13 @@ static Value builtinReflectIsExtensible(ExecutionState& state, Value thisValue,
|
|||
|
||||
// 1. If Type(target) is not Object, throw a TypeError exception.
|
||||
if (!target.isObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Reflect.string(), false, String::emptyString, "%s: The target of Reflect.isExtensible should be an Object");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, strings->Reflect.string(), false, String::emptyString, "%s: The target of Reflect.isExtensible should be an Object");
|
||||
}
|
||||
|
||||
// 2. Return target.[[IsExtensible]]().
|
||||
return Value(target.asObject()->isExtensible(state));
|
||||
bool result = target.asObject()->isExtensible(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
return Value(result);
|
||||
}
|
||||
|
||||
// https://www.ecma-international.org/ecma-262/6.0/#sec-reflect.preventextensions
|
||||
|
|
@ -212,11 +228,13 @@ static Value builtinReflectPreventExtensions(ExecutionState& state, Value thisVa
|
|||
|
||||
// 1. If Type(target) is not Object, throw a TypeError exception.
|
||||
if (!target.isObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Reflect.string(), false, String::emptyString, "%s: The target of Reflect.preventExtension should be an Object");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, strings->Reflect.string(), false, String::emptyString, "%s: The target of Reflect.preventExtension should be an Object");
|
||||
}
|
||||
|
||||
// 2. Return target.[[PreventExtensions]]().
|
||||
return Value(target.asObject()->preventExtensions(state));
|
||||
bool result = target.asObject()->preventExtensions(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
return Value(result);
|
||||
}
|
||||
|
||||
// https://www.ecma-international.org/ecma-262/6.0/#sec-reflect.ownkeys
|
||||
|
|
@ -227,11 +245,12 @@ static Value builtinReflectOwnKeys(ExecutionState& state, Value thisValue, size_
|
|||
|
||||
// 1. If Type(target) is not Object, throw a TypeError exception.
|
||||
if (!target.isObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Reflect.string(), false, String::emptyString, "%s: The target of Reflect.preventExtension should be an Object");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, strings->Reflect.string(), false, String::emptyString, "%s: The target of Reflect.preventExtension should be an Object");
|
||||
}
|
||||
// 2. Let keys be target.[[OwnPropertyKeys]]().
|
||||
// 3. ReturnIfAbrupt(keys).
|
||||
auto keys = target.asObject()->ownPropertyKeys(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// 4. Return CreateArrayFromList(keys).
|
||||
return Object::createArrayFromList(state, keys.size(), keys.data());
|
||||
}
|
||||
|
|
@ -245,18 +264,21 @@ static Value builtinReflectSet(ExecutionState& state, Value thisValue, size_t ar
|
|||
|
||||
// 1. If Type(target) is not Object, throw a TypeError exception.
|
||||
if (!target.isObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Reflect.string(), false, String::emptyString, "%s: The target of Reflect.set should be an Object");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, strings->Reflect.string(), false, String::emptyString, "%s: The target of Reflect.set should be an Object");
|
||||
}
|
||||
|
||||
// 2. Let key be ToPropertyKey(propertyKey).
|
||||
ObjectPropertyName key(state, argv[1]);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// 4. If receiver is not present, then
|
||||
// 4.a. Let receiver be target.
|
||||
Value receiver = argc > 3 ? argv[3] : target;
|
||||
|
||||
// 5. Return target.[[Set]](key, V, receiver).
|
||||
return Value(target.asObject()->set(state, key, argv[2], receiver));
|
||||
bool result = target.asObject()->set(state, key, argv[2], receiver);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
return Value(result);
|
||||
}
|
||||
|
||||
// https://www.ecma-international.org/ecma-262/6.0/#sec-reflect.setprototypeof
|
||||
|
|
@ -268,16 +290,18 @@ static Value builtinReflectSetPrototypeOf(ExecutionState& state, Value thisValue
|
|||
|
||||
// 1. If Type(target) is not Object, throw a TypeError exception.
|
||||
if (!target.isObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Reflect.string(), false, String::emptyString, "%s: The target of Reflect.setPrototypeOf should be an Object");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, strings->Reflect.string(), false, String::emptyString, "%s: The target of Reflect.setPrototypeOf should be an Object");
|
||||
}
|
||||
|
||||
// 2. If Type(proto) is not Object and proto is not null, throw a TypeError exception
|
||||
if (!proto.isObject() && !proto.isNull()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Reflect.string(), false, String::emptyString, "%s: The proto of Reflect.setPrototypeOf should be an Object or Null");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, strings->Reflect.string(), false, String::emptyString, "%s: The proto of Reflect.setPrototypeOf should be an Object or Null");
|
||||
}
|
||||
|
||||
// 3. Return target.[[SetPrototypeOf]](proto).
|
||||
return Value(target.asObject()->setPrototype(state, proto));
|
||||
bool result = target.asObject()->setPrototype(state, proto);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
return Value(result);
|
||||
}
|
||||
|
||||
void GlobalObject::initializeReflect(ExecutionState& state)
|
||||
|
|
|
|||
|
|
@ -32,10 +32,13 @@ static Value builtinRegExpConstructor(ExecutionState& state, Value thisValue, si
|
|||
Value pattern = argv[0];
|
||||
Value flags = argv[1];
|
||||
String* source = pattern.isUndefined() ? String::emptyString : pattern.toString(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
String* option = flags.isUndefined() ? String::emptyString : flags.toString(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// Let patternIsRegExp be IsRegExp(pattern).
|
||||
bool patternIsRegExp = argv[0].isObject() && argv[0].asObject()->isRegExp(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
if (!newTarget.hasValue()) {
|
||||
// Let newTarget be the active function object.
|
||||
|
|
@ -44,6 +47,7 @@ static Value builtinRegExpConstructor(ExecutionState& state, Value thisValue, si
|
|||
if (patternIsRegExp && flags.isUndefined()) {
|
||||
// Let patternConstructor be Get(pattern, "constructor").
|
||||
Value patternConstructor = pattern.asObject()->get(state, ObjectPropertyName(state.context()->staticStrings().constructor)).value(state, pattern);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// If SameValue(patternConstructor, newTarget), then return pattern.
|
||||
if (patternConstructor.isObject() && patternConstructor.asObject() == newTarget.value()) {
|
||||
return pattern;
|
||||
|
|
@ -59,19 +63,26 @@ static Value builtinRegExpConstructor(ExecutionState& state, Value thisValue, si
|
|||
// If flags is undefined, let F be the value of pattern’s [[OriginalFlags]] internal slot.
|
||||
// Else, let F be flags.
|
||||
option = flags.isUndefined() ? RegExpObject::computeRegExpOptionString(state, patternRegExp) : flags.toString(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
} else if (patternIsRegExp) {
|
||||
Value P = pattern.asObject()->get(state, ObjectPropertyName(state, state.context()->staticStrings().source)).value(state, pattern);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
source = P.isUndefined() ? String::emptyString : P.toString(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (flags.isUndefined()) {
|
||||
Value F = pattern.asObject()->get(state, ObjectPropertyName(state, state.context()->staticStrings().flags)).value(state, pattern);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
option = F.isUndefined() ? String::emptyString : F.toString(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
}
|
||||
}
|
||||
|
||||
Object* proto = Object::getPrototypeFromConstructor(state, newTarget.value(), [](ExecutionState& state, Context* constructorRealm) -> Object* {
|
||||
return constructorRealm->globalObject()->regexpPrototype();
|
||||
});
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
RegExpObject* regexp = new RegExpObject(state, proto, source, option);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
if (newTarget != state.context()->globalObject()->regexp()) {
|
||||
regexp->setLegacyFeaturesEnabled(false);
|
||||
|
|
@ -85,16 +96,18 @@ static Value builtinRegExpExec(ExecutionState& state, Value thisValue, size_t ar
|
|||
{
|
||||
RESOLVE_THIS_BINDING_TO_OBJECT(thisObject, RegExp, exec);
|
||||
if (!thisObject->isRegExpObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().RegExp.string(), true, state.context()->staticStrings().exec.string(), ErrorObject::Messages::GlobalObject_ThisNotRegExpObject);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().RegExp.string(), true, state.context()->staticStrings().exec.string(), ErrorObject::Messages::GlobalObject_ThisNotRegExpObject);
|
||||
}
|
||||
RegExpObject* regexp = thisObject->asRegExpObject();
|
||||
unsigned int option = regexp->option();
|
||||
String* str = argv[0].toString(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
uint64_t lastIndex = 0;
|
||||
if (option & (RegExpObject::Global | RegExpObject::Sticky)) {
|
||||
lastIndex = regexp->computedLastIndex(state);
|
||||
if (lastIndex > str->length()) {
|
||||
regexp->setLastIndex(state, Value(0));
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
return Value(Value::Null);
|
||||
}
|
||||
} else {
|
||||
|
|
@ -119,13 +132,16 @@ static Value builtinRegExpExec(ExecutionState& state, Value thisValue, size_t ar
|
|||
|
||||
if (option & (RegExpObject::Option::Sticky | RegExpObject::Option::Global)) {
|
||||
regexp->setLastIndex(state, Value(e));
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
}
|
||||
|
||||
return regexp->createRegExpMatchedArray(state, result, str);
|
||||
}
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
if (option & (RegExpObject::Option::Sticky | RegExpObject::Option::Global)) {
|
||||
regexp->setLastIndex(state, Value(0));
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
}
|
||||
|
||||
return Value(Value::Null);
|
||||
|
|
@ -136,13 +152,15 @@ static Value regExpExec(ExecutionState& state, Object* R, String* S)
|
|||
ASSERT(R->isObject());
|
||||
ASSERT(S->isString());
|
||||
Value exec = R->get(state, ObjectPropertyName(state.context()->staticStrings().exec)).value(state, R);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
Value arg[1] = { S };
|
||||
if (exec.isCallable()) {
|
||||
Value result = Object::call(state, exec, R, 1, arg);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (result.isNull() || result.isObject()) {
|
||||
return result;
|
||||
}
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().RegExp.string(), true, state.context()->staticStrings().test.string(), ErrorObject::Messages::GlobalObject_ThisNotObject);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().RegExp.string(), true, state.context()->staticStrings().test.string(), ErrorObject::Messages::GlobalObject_ThisNotObject);
|
||||
}
|
||||
return builtinRegExpExec(state, R, 1, arg, nullptr);
|
||||
}
|
||||
|
|
@ -151,16 +169,18 @@ static Value builtinRegExpTest(ExecutionState& state, Value thisValue, size_t ar
|
|||
{
|
||||
RESOLVE_THIS_BINDING_TO_OBJECT(thisObject, RegExp, test);
|
||||
if (!thisObject->isRegExpObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().RegExp.string(), true, state.context()->staticStrings().test.string(), ErrorObject::Messages::GlobalObject_ThisNotRegExpObject);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().RegExp.string(), true, state.context()->staticStrings().test.string(), ErrorObject::Messages::GlobalObject_ThisNotRegExpObject);
|
||||
}
|
||||
RegExpObject* regexp = thisObject->asRegExpObject();
|
||||
unsigned int option = regexp->option();
|
||||
String* str = argv[0].toString(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
uint64_t lastIndex = 0;
|
||||
if (option & (RegExpObject::Global | RegExpObject::Sticky)) {
|
||||
lastIndex = regexp->computedLastIndex(state);
|
||||
if (lastIndex > str->length()) {
|
||||
regexp->setLastIndex(state, Value(0));
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
return Value(false);
|
||||
}
|
||||
}
|
||||
|
|
@ -173,7 +193,7 @@ static Value builtinRegExpTest(ExecutionState& state, Value thisValue, size_t ar
|
|||
static Value builtinRegExpToString(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (!thisValue.isObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().RegExp.string(), true, state.context()->staticStrings().toString.string(), ErrorObject::Messages::GlobalObject_ThisNotObject);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().RegExp.string(), true, state.context()->staticStrings().toString.string(), ErrorObject::Messages::GlobalObject_ThisNotObject);
|
||||
}
|
||||
|
||||
Object* thisObject = thisValue.asObject();
|
||||
|
|
@ -187,6 +207,7 @@ static Value builtinRegExpToString(ExecutionState& state, Value thisValue, size_
|
|||
|
||||
if (!flagsValue.isUndefined()) {
|
||||
builder.appendString(flagsValue.toString(state));
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
} else {
|
||||
builder.appendString("\0");
|
||||
}
|
||||
|
|
@ -197,12 +218,12 @@ static Value builtinRegExpToString(ExecutionState& state, Value thisValue, size_
|
|||
static Value builtinRegExpCompile(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (!thisValue.isObject() || !thisValue.asObject()->isRegExpObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ThisNotRegExpObject);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ThisNotRegExpObject);
|
||||
}
|
||||
|
||||
if (argv[0].isObject() && argv[0].asObject()->isRegExpObject()) {
|
||||
if (!argv[1].isUndefined()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Cannot supply flags when constructing one RegExp from another");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Cannot supply flags when constructing one RegExp from another");
|
||||
} else {
|
||||
RegExpObject* retVal = thisValue.asPointerValue()->asObject()->asRegExpObject();
|
||||
RegExpObject* patternRegExp = argv[0].asPointerValue()->asObject()->asRegExpObject();
|
||||
|
|
@ -217,7 +238,9 @@ static Value builtinRegExpCompile(ExecutionState& state, Value thisValue, size_t
|
|||
|
||||
RegExpObject* retVal = thisValue.asPointerValue()->asObject()->asRegExpObject();
|
||||
String* pattern_str = argv[0].isUndefined() ? String::emptyString : argv[0].toString(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
String* flags_str = argv[1].isUndefined() ? String::emptyString : argv[1].toString(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
retVal->init(state, pattern_str, flags_str);
|
||||
return retVal;
|
||||
}
|
||||
|
|
@ -226,15 +249,21 @@ static Value builtinRegExpSearch(ExecutionState& state, Value thisValue, size_t
|
|||
// $21.2.5.9 RegExp.prototype[@@search]
|
||||
RESOLVE_THIS_BINDING_TO_OBJECT(rx, Object, search);
|
||||
String* s = argv[0].toString(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
Value previousLastIndex = rx->get(state, ObjectPropertyName(state.context()->staticStrings().lastIndex)).value(state, thisValue);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (!previousLastIndex.equalsToByTheSameValueAlgorithm(state, Value(0))) {
|
||||
rx->setThrowsException(state, ObjectPropertyName(state.context()->staticStrings().lastIndex), Value(0), thisValue);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
}
|
||||
Value result = regExpExec(state, rx, s);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
Value currentLastIndex = rx->get(state, ObjectPropertyName(state.context()->staticStrings().lastIndex)).value(state, thisValue);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (!previousLastIndex.equalsToByTheSameValueAlgorithm(state, currentLastIndex)) {
|
||||
rx->setThrowsException(state, ObjectPropertyName(state.context()->staticStrings().lastIndex), previousLastIndex, thisValue);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
}
|
||||
if (result.isNull()) {
|
||||
return Value(-1);
|
||||
|
|
@ -247,16 +276,21 @@ static Value builtinRegExpSearch(ExecutionState& state, Value thisValue, size_t
|
|||
static Value builtinRegExpSplit(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (!thisValue.isObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().object.string(), true, state.context()->staticStrings().replace.string(), ErrorObject::Messages::GlobalObject_ThisUndefinedOrNull);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().object.string(), true, state.context()->staticStrings().replace.string(), ErrorObject::Messages::GlobalObject_ThisUndefinedOrNull);
|
||||
}
|
||||
Object* rx = thisValue.asObject();
|
||||
String* S = argv[0].toString(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// Let C be SpeciesConstructor(rx, %RegExp%).
|
||||
Value C = rx->speciesConstructor(state, state.context()->globalObject()->regexp());
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// Let flags be ToString(Get(rx, "flags")).
|
||||
String* flags = rx->get(state, ObjectPropertyName(state.context()->staticStrings().flags)).value(state, rx).toString(state);
|
||||
Value flagsValue = rx->get(state, ObjectPropertyName(state.context()->staticStrings().flags)).value(state, rx);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
String* flags = flagsValue.toString(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
bool unicodeMatching = false;
|
||||
|
||||
String* newFlags;
|
||||
|
|
@ -276,7 +310,10 @@ static Value builtinRegExpSplit(ExecutionState& state, Value thisValue, size_t a
|
|||
|
||||
// Let splitter be Construct(C, <<rx, newFlags>>).
|
||||
Value params[2] = { rx, newFlags };
|
||||
Object* splitter = Object::construct(state, C, 2, params).toObject(state);
|
||||
Value splitterValue = Object::construct(state, C, 2, params);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
Object* splitter = splitterValue.toObject(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// Let A be ArrayCreate(0).
|
||||
ArrayObject* A = new ArrayObject(state);
|
||||
|
|
@ -302,12 +339,14 @@ static Value builtinRegExpSplit(ExecutionState& state, Value thisValue, size_t a
|
|||
// Let z be RegExpExec(splitter, S).
|
||||
|
||||
Value z = regExpExec(state, splitter, S);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// If z is not null, return A.
|
||||
if (!z.isNull()) {
|
||||
return A;
|
||||
}
|
||||
// Perform CreateDataProperty(A, "0", S).
|
||||
A->defineOwnPropertyThrowsException(state, ObjectPropertyName(state, Value(0)), ObjectPropertyDescriptor(S, (ObjectPropertyDescriptor::AllPresent)));
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Return A.
|
||||
return A;
|
||||
}
|
||||
|
|
@ -318,15 +357,20 @@ static Value builtinRegExpSplit(ExecutionState& state, Value thisValue, size_t a
|
|||
while (q < size) {
|
||||
// Let setStatus be Set(splitter, "lastIndex", q, true).
|
||||
splitter->setThrowsException(state, ObjectPropertyName(state.context()->staticStrings().lastIndex), Value(q), splitter);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Let z be RegExpExec(splitter, S).
|
||||
Value z = regExpExec(state, splitter, S);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// If z is null, let q be AdvanceStringIndex(S, q, unicodeMatching).
|
||||
if (z.isNull()) {
|
||||
q = S->advanceStringIndex(q, unicodeMatching);
|
||||
} else {
|
||||
// Else z is not null,
|
||||
// Let e be ToLength(Get(splitter, "lastIndex")).
|
||||
size_t e = splitter->get(state, ObjectPropertyName(state.context()->staticStrings().lastIndex)).value(state, splitter).toLength(state);
|
||||
Value eValue = splitter->get(state, ObjectPropertyName(state.context()->staticStrings().lastIndex)).value(state, splitter);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
size_t e = eValue.toLength(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (e > size) {
|
||||
e = size;
|
||||
}
|
||||
|
|
@ -335,7 +379,10 @@ static Value builtinRegExpSplit(ExecutionState& state, Value thisValue, size_t a
|
|||
q = S->advanceStringIndex(q, unicodeMatching);
|
||||
} else {
|
||||
// Else e != p
|
||||
size_t matchStart = z.asObject()->get(state, ObjectPropertyName(state.context()->staticStrings().index)).value(state, z).toNumber(state);
|
||||
Value matchStartValue = z.asObject()->get(state, ObjectPropertyName(state.context()->staticStrings().index)).value(state, z);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
size_t matchStart = matchStartValue.toNumber(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
if (matchStart >= S->length()) {
|
||||
matchStart = p;
|
||||
|
|
@ -344,6 +391,7 @@ static Value builtinRegExpSplit(ExecutionState& state, Value thisValue, size_t a
|
|||
String* T = S->substring(p, matchStart);
|
||||
// Perform CreateDataProperty(A, ToString(lengthA), T).
|
||||
A->defineOwnPropertyThrowsException(state, ObjectPropertyName(state, Value(lengthA).toString(state)), ObjectPropertyDescriptor(T, (ObjectPropertyDescriptor::AllPresent)));
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Let lengthA be lengthA + 1.
|
||||
lengthA++;
|
||||
// If lengthA = lim, return A.
|
||||
|
|
@ -353,7 +401,10 @@ static Value builtinRegExpSplit(ExecutionState& state, Value thisValue, size_t a
|
|||
// Let p be e.
|
||||
p = e;
|
||||
// Let numberOfCaptures be ToLength(Get(z, "length")).
|
||||
size_t numberOfCaptures = z.asObject()->get(state, ObjectPropertyName(state.context()->staticStrings().length)).value(state, z).toLength(state);
|
||||
Value numberOfCapturesValue = z.asObject()->get(state, ObjectPropertyName(state.context()->staticStrings().length)).value(state, z);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
size_t numberOfCaptures = numberOfCapturesValue.toLength(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Let numberOfCaptures be max(numberOfCaptures - 1, 0).
|
||||
numberOfCaptures = std::max(numberOfCaptures - 1, (size_t)0);
|
||||
if (numberOfCaptures == SIZE_MAX) {
|
||||
|
|
@ -364,8 +415,10 @@ static Value builtinRegExpSplit(ExecutionState& state, Value thisValue, size_t a
|
|||
for (size_t i = 1; i <= numberOfCaptures; i++) {
|
||||
// Let nextCapture be Get(z, ToString(i)).
|
||||
Value nextCapture = z.asObject()->get(state, ObjectPropertyName(state, Value(i).toString(state))).value(state, z);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Perform CreateDataProperty(A, ToString(lengthA), nextCapture).
|
||||
A->defineOwnPropertyThrowsException(state, ObjectPropertyName(state, Value(lengthA).toString(state)), ObjectPropertyDescriptor(nextCapture, ObjectPropertyDescriptor::AllPresent));
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Let lengthA be lengthA + 1.
|
||||
lengthA++;
|
||||
// If lengthA = lim, return A.
|
||||
|
|
@ -383,6 +436,7 @@ static Value builtinRegExpSplit(ExecutionState& state, Value thisValue, size_t a
|
|||
String* T = S->substring(p, size);
|
||||
// Perform CreateDataProperty(A, ToString(lengthA), T ).
|
||||
A->defineOwnPropertyThrowsException(state, ObjectPropertyName(state, Value(lengthA).toString(state)), ObjectPropertyDescriptor(T, ObjectPropertyDescriptor::AllPresent));
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Return A.
|
||||
return A;
|
||||
}
|
||||
|
|
@ -392,9 +446,10 @@ static Value builtinRegExpReplace(ExecutionState& state, Value thisValue, size_t
|
|||
ASSERT(argc == 0 || argv != nullptr);
|
||||
Value rx = thisValue;
|
||||
if (!thisValue.isObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().object.string(), true, state.context()->staticStrings().replace.string(), ErrorObject::Messages::GlobalObject_ThisUndefinedOrNull);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().object.string(), true, state.context()->staticStrings().replace.string(), ErrorObject::Messages::GlobalObject_ThisUndefinedOrNull);
|
||||
}
|
||||
String* str = argv[0].toString(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
Value replaceValue = argv[1];
|
||||
size_t lengthStr = str->length();
|
||||
bool functionalReplace = replaceValue.isCallable();
|
||||
|
|
@ -405,16 +460,23 @@ static Value builtinRegExpReplace(ExecutionState& state, Value thisValue, size_t
|
|||
|
||||
if (!functionalReplace) {
|
||||
replaceValue = replaceValue.toString(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
}
|
||||
bool global = rx.asObject()->get(state, ObjectPropertyName(state, state.context()->staticStrings().global)).value(state, rx).toBoolean(state);
|
||||
Value globalValue = rx.asObject()->get(state, ObjectPropertyName(state, state.context()->staticStrings().global)).value(state, rx);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
bool global = globalValue.toBoolean(state);
|
||||
if (global) {
|
||||
fullUnicode = rx.asObject()->get(state, ObjectPropertyName(state, state.context()->staticStrings().unicode)).value(state, rx).toBoolean(state);
|
||||
Value val = rx.asObject()->get(state, ObjectPropertyName(state, state.context()->staticStrings().unicode)).value(state, rx);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
fullUnicode = val.toBoolean(state);
|
||||
rx.asObject()->setThrowsException(state, ObjectPropertyName(state, state.context()->staticStrings().lastIndex), Value(0), rx);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
}
|
||||
ValueVectorWithInlineStorage results;
|
||||
Value strValue = Value(str);
|
||||
while (true) {
|
||||
Value result = regExpExec(state, rx.toObject(state), str);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (result.isNull()) {
|
||||
break;
|
||||
}
|
||||
|
|
@ -423,24 +485,38 @@ static Value builtinRegExpReplace(ExecutionState& state, Value thisValue, size_t
|
|||
break;
|
||||
}
|
||||
Value matchStr = result.asObject()->get(state, ObjectPropertyName(state, Value(0))).value(state, result);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (matchStr.toString(state)->length() == 0 && global) {
|
||||
uint64_t thisIndex = rx.asObject()->get(state, ObjectPropertyName(state, state.context()->staticStrings().lastIndex)).value(state, rx).toLength(state);
|
||||
Value thisIndexValue = rx.asObject()->get(state, ObjectPropertyName(state, state.context()->staticStrings().lastIndex)).value(state, rx);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
uint64_t thisIndex = thisIndexValue.toLength(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
uint64_t nextIndex = str->advanceStringIndex(thisIndex, fullUnicode);
|
||||
rx.asObject()->setThrowsException(state, ObjectPropertyName(state, state.context()->staticStrings().lastIndex), Value(nextIndex), rx);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
}
|
||||
}
|
||||
|
||||
size_t resultSize = results.size();
|
||||
for (size_t i = 0; i < resultSize; i++) {
|
||||
Object* result = results[i].toObject(state);
|
||||
size_t nCaptures = result->get(state, ObjectPropertyName(state.context()->staticStrings().length)).value(state, result).toLength(state) - 1;
|
||||
Value nCapturesValue = result->get(state, ObjectPropertyName(state.context()->staticStrings().length)).value(state, result);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
size_t nCaptures = nCapturesValue.toLength(state) - 1;
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
if (nCaptures == SIZE_MAX) {
|
||||
nCaptures = 0;
|
||||
}
|
||||
String* matched = result->get(state, ObjectPropertyName(state, Value(0))).value(state, result).toString(state);
|
||||
Value matchedValue = result->get(state, ObjectPropertyName(state, Value(0))).value(state, result);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
String* matched = matchedValue.toString(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
size_t matchLength = matched->length();
|
||||
size_t position = result->get(state, ObjectPropertyName(state.context()->staticStrings().index)).value(state, result).toInteger(state);
|
||||
Value positionValue = result->get(state, ObjectPropertyName(state.context()->staticStrings().index)).value(state, result);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
size_t position = positionValue.toInteger(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
if (position > lengthStr) {
|
||||
position = lengthStr;
|
||||
|
|
@ -452,6 +528,7 @@ static Value builtinRegExpReplace(ExecutionState& state, Value thisValue, size_t
|
|||
StringVector captures;
|
||||
Value* replacerArgs = nullptr;
|
||||
Value namedCaptures = result->get(state, ObjectPropertyName(state, state.context()->staticStrings().groups)).value(state, result);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
size_t replacerArgsSize = nCaptures + 3;
|
||||
if (functionalReplace) {
|
||||
if (namedCaptures.isUndefined()) {
|
||||
|
|
@ -465,8 +542,10 @@ static Value builtinRegExpReplace(ExecutionState& state, Value thisValue, size_t
|
|||
}
|
||||
while (n <= nCaptures) {
|
||||
Value capN = result->get(state, ObjectPropertyName(state, Value(n))).value(state, result);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (!capN.isUndefined()) {
|
||||
captures.push_back(capN.toString(state));
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
} else {
|
||||
captures.push_back(String::emptyString);
|
||||
}
|
||||
|
|
@ -479,10 +558,13 @@ static Value builtinRegExpReplace(ExecutionState& state, Value thisValue, size_t
|
|||
replacerArgs[nCaptures + 1] = Value((size_t)position);
|
||||
replacerArgs[nCaptures + 2] = Value(str);
|
||||
|
||||
replacement = Object::call(state, replaceValue, Value(), replacerArgsSize, replacerArgs).toString(state);
|
||||
Value res = Object::call(state, replaceValue, Value(), replacerArgsSize, replacerArgs);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
replacement = res.toString(state);
|
||||
} else {
|
||||
replacement = String::getSubstitution(state, matched, str, position, captures, namedCaptures, replaceValue.toString(state));
|
||||
}
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (position >= nextSourcePosition) {
|
||||
builder.appendSubString(str, nextSourcePosition, position);
|
||||
builder.appendSubString(replacement, 0, replacement->length());
|
||||
|
|
@ -501,22 +583,28 @@ static Value builtinRegExpMatch(ExecutionState& state, Value thisValue, size_t a
|
|||
Value rx = thisValue;
|
||||
|
||||
if (!rx.isObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().RegExp.string(), true,
|
||||
state.context()->staticStrings().toPrimitive.string(), ErrorObject::Messages::GlobalObject_ThisNotObject);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().RegExp.string(), true,
|
||||
state.context()->staticStrings().toPrimitive.string(), ErrorObject::Messages::GlobalObject_ThisNotObject);
|
||||
}
|
||||
|
||||
String* str = argv[0].toString(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
ASSERT(str != nullptr);
|
||||
|
||||
//21.2.5.6.8
|
||||
bool global = rx.asObject()->get(state, ObjectPropertyName(state, state.context()->staticStrings().global)).value(state, rx).toBoolean(state);
|
||||
Value globalValue = rx.asObject()->get(state, ObjectPropertyName(state, state.context()->staticStrings().global)).value(state, rx);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
bool global = globalValue.toBoolean(state);
|
||||
|
||||
if (!global) {
|
||||
return regExpExec(state, rx.asObject(), str);
|
||||
}
|
||||
|
||||
bool fullUnicode = rx.asObject()->get(state, ObjectPropertyName(state, state.context()->staticStrings().unicode)).value(state, rx).toBoolean(state);
|
||||
Value fullUnicodeValue = rx.asObject()->get(state, ObjectPropertyName(state, state.context()->staticStrings().unicode)).value(state, rx);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
bool fullUnicode = fullUnicodeValue.toBoolean(state);
|
||||
rx.asObject()->setThrowsException(state, ObjectPropertyName(state, state.context()->staticStrings().lastIndex), Value(0), rx);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
ArrayObject* A = new ArrayObject(state);
|
||||
size_t n = 0;
|
||||
|
||||
|
|
@ -524,6 +612,7 @@ static Value builtinRegExpMatch(ExecutionState& state, Value thisValue, size_t a
|
|||
while (true) {
|
||||
//21.2.5.6.8.g.i
|
||||
Value result = regExpExec(state, rx.asObject(), str);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
//21.2.5.6.8.g.iii
|
||||
if (result.isNull()) {
|
||||
if (n == 0) {
|
||||
|
|
@ -532,13 +621,22 @@ static Value builtinRegExpMatch(ExecutionState& state, Value thisValue, size_t a
|
|||
return A;
|
||||
} else {
|
||||
//21.2.5.6.8.g.iv
|
||||
Value matchStr = result.asObject()->get(state, ObjectPropertyName(state, Value(0))).value(state, result).toString(state);
|
||||
Value matchStr = result.asObject()->get(state, ObjectPropertyName(state, Value(0))).value(state, result);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
matchStr = matchStr.toString(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
A->defineOwnProperty(state, ObjectPropertyName(state, Value(n).toString(state)), ObjectPropertyDescriptor(Value(matchStr), (ObjectPropertyDescriptor::PresentAttribute::AllPresent)));
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (matchStr.asString()->length() == 0) {
|
||||
//21.2.5.6.8.g.iv.5
|
||||
uint64_t thisIndex = rx.asObject()->get(state, ObjectPropertyName(state, state.context()->staticStrings().lastIndex)).value(state, rx).toLength(state);
|
||||
Value thisIndexValue = rx.asObject()->get(state, ObjectPropertyName(state, state.context()->staticStrings().lastIndex)).value(state, rx);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
uint64_t thisIndex = thisIndexValue.toLength(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
uint64_t nextIndex = str->advanceStringIndex(thisIndex, fullUnicode);
|
||||
rx.asObject()->setThrowsException(state, state.context()->staticStrings().lastIndex, Value(nextIndex), rx);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
}
|
||||
n++;
|
||||
}
|
||||
|
|
@ -548,21 +646,33 @@ static Value builtinRegExpMatch(ExecutionState& state, Value thisValue, size_t a
|
|||
static Value builtinRegExpMatchAll(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (!thisValue.isObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().RegExp.string(), true,
|
||||
state.context()->staticStrings().toPrimitive.string(), ErrorObject::Messages::GlobalObject_ThisNotObject);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().RegExp.string(), true,
|
||||
state.context()->staticStrings().toPrimitive.string(), ErrorObject::Messages::GlobalObject_ThisNotObject);
|
||||
}
|
||||
bool global = false;
|
||||
bool unicode = false;
|
||||
Object* thisObj = thisValue.asObject();
|
||||
String* s = argv[0].toString(state);
|
||||
String* flags = thisObj->get(state, ObjectPropertyName(state, state.context()->staticStrings().flags)).value(state, thisObj).toString(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
Value flagsValue = thisObj->get(state, ObjectPropertyName(state, state.context()->staticStrings().flags)).value(state, thisObj);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
String* flags = flagsValue.toString(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
Value c = thisObj->speciesConstructor(state, state.context()->globalObject()->regexp());
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
Value arguments[] = { thisObj, flags };
|
||||
Object* matcher = Object::construct(state, c, 2, arguments).toObject(state);
|
||||
Value matcherValue = Object::construct(state, c, 2, arguments);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
Object* matcher = matcherValue.toObject(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
size_t lastIndex = thisObj->get(state, ObjectPropertyName(state, state.context()->staticStrings().lastIndex)).value(state, thisObj).toNumber(state);
|
||||
Value lastIndexValue = thisObj->get(state, ObjectPropertyName(state, state.context()->staticStrings().lastIndex)).value(state, thisObj);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
size_t lastIndex = lastIndexValue.toNumber(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
matcher->asRegExpObject()->setLastIndex(state, Value(lastIndex));
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
if (flags->find("g") != SIZE_MAX) {
|
||||
global = true;
|
||||
|
|
@ -577,14 +687,14 @@ static Value builtinRegExpMatchAll(ExecutionState& state, Value thisValue, size_
|
|||
static Value builtinRegExpOptionGetterHelper(ExecutionState& state, Value thisValue, unsigned int option)
|
||||
{
|
||||
if (!thisValue.isObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ThisNotObject);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ThisNotObject);
|
||||
}
|
||||
|
||||
if (!thisValue.asObject()->isRegExpObject()) {
|
||||
if (thisValue.asObject() == state.context()->globalObject()->regexpPrototype()) {
|
||||
return Value();
|
||||
} else {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ThisNotRegExpObject);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ThisNotRegExpObject);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -594,7 +704,7 @@ static Value builtinRegExpOptionGetterHelper(ExecutionState& state, Value thisVa
|
|||
static Value builtinRegExpFlagsGetter(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (!thisValue.isObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "getter called on non-object");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "getter called on non-object");
|
||||
}
|
||||
|
||||
return Value(RegExpObject::computeRegExpOptionString(state, thisValue.asObject()));
|
||||
|
|
@ -623,14 +733,14 @@ static Value builtinRegExpMultiLineGetter(ExecutionState& state, Value thisValue
|
|||
static Value builtinRegExpSourceGetter(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (!thisValue.isObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ThisNotObject);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ThisNotObject);
|
||||
}
|
||||
|
||||
if (!thisValue.asObject()->isRegExpObject()) {
|
||||
if (thisValue.asObject() == state.context()->globalObject()->regexpPrototype()) {
|
||||
return Value(state.context()->staticStrings().defaultRegExpString.string());
|
||||
} else {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ThisNotRegExpObject);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ThisNotRegExpObject);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -652,11 +762,11 @@ static Value builtinRegExpUnicodeGetter(ExecutionState& state, Value thisValue,
|
|||
static Value builtinRegExpInputGetter(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (!thisValue.isObject() || thisValue.asObject() != state.context()->globalObject()->regexp()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ThisNotRegExpObject);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ThisNotRegExpObject);
|
||||
}
|
||||
auto& status = state.context()->regexpLegacyFeatures();
|
||||
if (!status.isValid()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::String_InvalidStringLength);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::String_InvalidStringLength);
|
||||
}
|
||||
return status.input;
|
||||
}
|
||||
|
|
@ -664,9 +774,10 @@ static Value builtinRegExpInputGetter(ExecutionState& state, Value thisValue, si
|
|||
static Value builtinRegExpInputSetter(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (!thisValue.isObject() || thisValue.asObject() != state.context()->globalObject()->regexp()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ThisNotRegExpObject);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ThisNotRegExpObject);
|
||||
}
|
||||
state.context()->regexpLegacyFeatures().input = argv[0].toString(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
return Value();
|
||||
}
|
||||
|
||||
|
|
@ -691,12 +802,12 @@ static Value builtinRegExpInputSetter(ExecutionState& state, Value thisValue, si
|
|||
static Value builtinRegExp##NAME##Getter(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget) \
|
||||
{ \
|
||||
if (!thisValue.isObject() || thisValue.asObject() != state.context()->globalObject()->regexp()) { \
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ThisNotRegExpObject); \
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ThisNotRegExpObject); \
|
||||
} \
|
||||
\
|
||||
auto& status = state.context()->regexpLegacyFeatures(); \
|
||||
if (!status.isValid()) { \
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::String_InvalidStringLength); \
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::String_InvalidStringLength); \
|
||||
} \
|
||||
return new StringView(status.name); \
|
||||
}
|
||||
|
|
@ -705,11 +816,11 @@ static Value builtinRegExpInputSetter(ExecutionState& state, Value thisValue, si
|
|||
static Value builtinRegExpDollar##number##Getter(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget) \
|
||||
{ \
|
||||
if (!thisValue.isObject() || thisValue.asObject() != state.context()->globalObject()->regexp()) { \
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ThisNotRegExpObject); \
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ThisNotRegExpObject); \
|
||||
} \
|
||||
auto& status = state.context()->regexpLegacyFeatures(); \
|
||||
if (!status.isValid()) { \
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::String_InvalidStringLength); \
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::String_InvalidStringLength); \
|
||||
} \
|
||||
return (status.dollarCount < number) ? String::emptyString : new StringView(status.dollars[number - 1]); \
|
||||
}
|
||||
|
|
@ -720,7 +831,7 @@ REGEXP_LEGACY_DOLLAR_NUMBER_FEATURES(DEFINE_LEGACY_DOLLAR_NUMBER_FEATURE_GETTER)
|
|||
static Value builtinRegExpStringIteratorNext(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (!thisValue.isObject() || !thisValue.asObject()->isRegExpStringIteratorObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().RegExpStringIterator.string(), true, state.context()->staticStrings().next.string(), ErrorObject::Messages::GlobalObject_CalledOnIncompatibleReceiver);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().RegExpStringIterator.string(), true, state.context()->staticStrings().next.string(), ErrorObject::Messages::GlobalObject_CalledOnIncompatibleReceiver);
|
||||
}
|
||||
RegExpStringIteratorObject* iter = thisValue.asObject()->asIteratorObject()->asRegExpStringIteratorObject();
|
||||
return iter->next(state);
|
||||
|
|
@ -742,12 +853,25 @@ std::pair<Value, bool> RegExpStringIteratorObject::advance(ExecutionState& state
|
|||
return std::make_pair(Value(), true);
|
||||
}
|
||||
if (global) {
|
||||
String* matchStr = match.asObject()->get(state, ObjectPropertyName(state, Value(0))).value(state, match).toString(state);
|
||||
Value matchValue = match.asObject()->get(state, ObjectPropertyName(state, Value(0))).value(state, match);
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
return std::make_pair(Value(Value::Exception), false);
|
||||
}
|
||||
String* matchStr = matchValue.toString(state);
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
return std::make_pair(Value(Value::Exception), false);
|
||||
}
|
||||
if (matchStr->length() == 0) {
|
||||
//21.2.5.6.8.g.iv.5
|
||||
uint64_t thisIndex = r->get(state, ObjectPropertyName(state, state.context()->staticStrings().lastIndex)).value(state, r).toLength(state);
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
return std::make_pair(Value(Value::Exception), false);
|
||||
}
|
||||
uint64_t nextIndex = s->advanceStringIndex(thisIndex, unicode);
|
||||
r->setThrowsException(state, state.context()->staticStrings().lastIndex, Value(nextIndex), r);
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
return std::make_pair(Value(Value::Exception), false);
|
||||
}
|
||||
}
|
||||
return std::make_pair(match, false);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,8 +31,7 @@ static Value builtinSetConstructor(ExecutionState& state, Value thisValue, size_
|
|||
{
|
||||
// If NewTarget is undefined, throw a TypeError exception.
|
||||
if (!newTarget.hasValue()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ConstructorRequiresNew);
|
||||
return Value();
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ConstructorRequiresNew);
|
||||
}
|
||||
|
||||
// Let set be ? OrdinaryCreateFromConstructor(NewTarget, "%SetPrototype%", « [[SetData]] »).
|
||||
|
|
@ -40,6 +39,7 @@ static Value builtinSetConstructor(ExecutionState& state, Value thisValue, size_
|
|||
Object* proto = Object::getPrototypeFromConstructor(state, newTarget.value(), [](ExecutionState& state, Context* constructorRealm) -> Object* {
|
||||
return constructorRealm->globalObject()->setPrototype();
|
||||
});
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
SetObject* set = new SetObject(state, proto);
|
||||
|
||||
// If iterable is not present, let iterable be undefined.
|
||||
|
|
@ -55,31 +55,34 @@ static Value builtinSetConstructor(ExecutionState& state, Value thisValue, size_
|
|||
|
||||
// Let adder be ? Get(set, "add").
|
||||
Value adder = set->get(state, ObjectPropertyName(state.context()->staticStrings().add)).value(state, set);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// If IsCallable(adder) is false, throw a TypeError exception.
|
||||
if (!adder.isCallable()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::NOT_Callable);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::NOT_Callable);
|
||||
}
|
||||
// Let iteratorRecord be ? GetIterator(iterable).
|
||||
auto iteratorRecord = IteratorObject::getIterator(state, iterable);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// Repeat
|
||||
while (true) {
|
||||
// Let next be ? IteratorStep(iteratorRecord).
|
||||
auto next = IteratorObject::iteratorStep(state, iteratorRecord);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// If next is false, return set.
|
||||
if (!next.hasValue()) {
|
||||
return set;
|
||||
}
|
||||
// Let nextValue be ? IteratorValue(next).
|
||||
Value nextValue = IteratorObject::iteratorValue(state, next.value());
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// Let status be Call(adder, set, « nextValue »).
|
||||
try {
|
||||
Value argv[1] = { nextValue };
|
||||
Object::call(state, adder, set, 1, argv);
|
||||
} catch (const Value& v) {
|
||||
Value argv[1] = { nextValue };
|
||||
Object::call(state, adder, set, 1, argv);
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
// we should save thrown value bdwgc cannot track thrown value
|
||||
Value exceptionValue = v;
|
||||
Value exceptionValue = state.detachPendingException();
|
||||
// If status is an abrupt completion, return ? IteratorClose(iteratorRecord, status).
|
||||
return IteratorObject::iteratorClose(state, iteratorRecord, exceptionValue, true);
|
||||
}
|
||||
|
|
@ -88,10 +91,10 @@ static Value builtinSetConstructor(ExecutionState& state, Value thisValue, size_
|
|||
return set;
|
||||
}
|
||||
|
||||
#define RESOLVE_THIS_BINDING_TO_SET(NAME, OBJ, BUILT_IN_METHOD) \
|
||||
if (!thisValue.isObject() || !thisValue.asObject()->isSetObject()) { \
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().OBJ.string(), true, state.context()->staticStrings().BUILT_IN_METHOD.string(), ErrorObject::Messages::GlobalObject_CalledOnIncompatibleReceiver); \
|
||||
} \
|
||||
#define RESOLVE_THIS_BINDING_TO_SET(NAME, OBJ, BUILT_IN_METHOD) \
|
||||
if (!thisValue.isObject() || !thisValue.asObject()->isSetObject()) { \
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().OBJ.string(), true, state.context()->staticStrings().BUILT_IN_METHOD.string(), ErrorObject::Messages::GlobalObject_CalledOnIncompatibleReceiver); \
|
||||
} \
|
||||
SetObject* NAME = thisValue.asObject()->asSetObject();
|
||||
|
||||
static Value builtinSetAdd(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
|
|
@ -130,7 +133,7 @@ static Value builtinSetForEach(ExecutionState& state, Value thisValue, size_t ar
|
|||
Value callbackfn = argv[0];
|
||||
// If IsCallable(callbackfn) is false, throw a TypeError exception.
|
||||
if (!callbackfn.isCallable()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().Set.string(), true, state.context()->staticStrings().forEach.string(), ErrorObject::Messages::GlobalObject_CallbackNotCallable);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Set.string(), true, state.context()->staticStrings().forEach.string(), ErrorObject::Messages::GlobalObject_CallbackNotCallable);
|
||||
}
|
||||
// If thisArg was supplied, let T be thisArg; else let T be undefined.
|
||||
Value T;
|
||||
|
|
@ -148,6 +151,7 @@ static Value builtinSetForEach(ExecutionState& state, Value thisValue, size_t ar
|
|||
// Perform ? Call(callbackfn, T, « e, e, S »).
|
||||
Value argv[3] = { Value(e), Value(e), Value(S) };
|
||||
Object::call(state, callbackfn, T, 3, argv);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -175,7 +179,7 @@ static Value builtinSetSizeGetter(ExecutionState& state, Value thisValue, size_t
|
|||
static Value builtinSetIteratorNext(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (!thisValue.isObject() || !thisValue.asObject()->isSetIteratorObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().SetIterator.string(), true, state.context()->staticStrings().next.string(), ErrorObject::Messages::GlobalObject_CalledOnIncompatibleReceiver);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().SetIterator.string(), true, state.context()->staticStrings().next.string(), ErrorObject::Messages::GlobalObject_CalledOnIncompatibleReceiver);
|
||||
}
|
||||
SetIteratorObject* iter = thisValue.asObject()->asIteratorObject()->asSetIteratorObject();
|
||||
return iter->next(state);
|
||||
|
|
|
|||
|
|
@ -32,12 +32,13 @@ namespace Escargot {
|
|||
static Value builtinSharedArrayBufferConstructor(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (!newTarget.hasValue()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ConstructorRequiresNew);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ConstructorRequiresNew);
|
||||
}
|
||||
|
||||
uint64_t byteLength = argv[0].toIndex(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (byteLength == Value::InvalidIndexValue) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, state.context()->staticStrings().SharedArrayBuffer.string(), false, String::emptyString, ErrorObject::Messages::GlobalObject_FirstArgumentInvalidLength);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::RangeError, state.context()->staticStrings().SharedArrayBuffer.string(), false, String::emptyString, ErrorObject::Messages::GlobalObject_FirstArgumentInvalidLength);
|
||||
}
|
||||
|
||||
Optional<uint64_t> maxByteLength;
|
||||
|
|
@ -45,22 +46,26 @@ static Value builtinSharedArrayBufferConstructor(ExecutionState& state, Value th
|
|||
if (UNLIKELY((argc > 1) && argv[1].isObject())) {
|
||||
Object* options = argv[1].asObject();
|
||||
Value maxLengthValue = options->get(state, ObjectPropertyName(state.context()->staticStrings().maxByteLength)).value(state, options);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (!maxLengthValue.isUndefined()) {
|
||||
maxByteLength = maxLengthValue.toIndex(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (UNLIKELY((maxByteLength.value() == Value::InvalidIndexValue) || (byteLength > maxByteLength.value()))) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, state.context()->staticStrings().SharedArrayBuffer.string(), false, String::emptyString, ErrorObject::Messages::GlobalObject_InvalidArrayLength);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::RangeError, state.context()->staticStrings().SharedArrayBuffer.string(), false, String::emptyString, ErrorObject::Messages::GlobalObject_InvalidArrayLength);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return SharedArrayBufferObject::allocateSharedArrayBuffer(state, newTarget.value(), byteLength, maxByteLength);
|
||||
SharedArrayBufferObject* result = SharedArrayBufferObject::allocateSharedArrayBuffer(state, newTarget.value(), byteLength, maxByteLength);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
return result;
|
||||
}
|
||||
|
||||
#define RESOLVE_THIS_BINDING_TO_SHAREDARRAYBUFFER(NAME, OBJ, BUILT_IN_METHOD) \
|
||||
if (UNLIKELY(!thisValue.isObject() || !thisValue.asObject()->isSharedArrayBufferObject())) { \
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().OBJ.string(), true, state.context()->staticStrings().BUILT_IN_METHOD.string(), ErrorObject::Messages::GlobalObject_CalledOnIncompatibleReceiver); \
|
||||
} \
|
||||
\
|
||||
#define RESOLVE_THIS_BINDING_TO_SHAREDARRAYBUFFER(NAME, OBJ, BUILT_IN_METHOD) \
|
||||
if (UNLIKELY(!thisValue.isObject() || !thisValue.asObject()->isSharedArrayBufferObject())) { \
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().OBJ.string(), true, state.context()->staticStrings().BUILT_IN_METHOD.string(), ErrorObject::Messages::GlobalObject_CalledOnIncompatibleReceiver); \
|
||||
} \
|
||||
\
|
||||
SharedArrayBufferObject* NAME = thisValue.asObject()->asSharedArrayBufferObject();
|
||||
|
||||
// https://262.ecma-international.org/#sec-get-sharedarraybuffer.prototype.bytelength
|
||||
|
|
@ -92,14 +97,14 @@ static Value builtinSharedArrayBufferGrow(ExecutionState& state, Value thisValue
|
|||
RESOLVE_THIS_BINDING_TO_SHAREDARRAYBUFFER(O, SharedArrayBuffer, grow);
|
||||
|
||||
if (!O->isResizableArrayBuffer()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().SharedArrayBuffer.string(), true, state.context()->staticStrings().grow.string(), "SharedArrayBuffer is not a growable buffer");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().SharedArrayBuffer.string(), true, state.context()->staticStrings().grow.string(), "SharedArrayBuffer is not a growable buffer");
|
||||
}
|
||||
|
||||
// Let newByteLength to ? ToIntegerOrInfinity(newLength).
|
||||
auto newByteLength = argv[0].toInteger(state);
|
||||
|
||||
if ((newByteLength < O->byteLength()) || (newByteLength > O->maxByteLength())) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, state.context()->staticStrings().SharedArrayBuffer.string(), true, state.context()->staticStrings().grow.string(), ErrorObject::Messages::GlobalObject_FirstArgumentInvalidLength);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::RangeError, state.context()->staticStrings().SharedArrayBuffer.string(), true, state.context()->staticStrings().grow.string(), ErrorObject::Messages::GlobalObject_FirstArgumentInvalidLength);
|
||||
}
|
||||
|
||||
O->backingStore()->resize(static_cast<size_t>(newByteLength));
|
||||
|
|
@ -119,15 +124,17 @@ static Value builtinSharedArrayBufferSlice(ExecutionState& state, Value thisValu
|
|||
size_t newLen = std::max((int)final_ - (int)first, 0);
|
||||
|
||||
Value constructor = O->speciesConstructor(state, state.context()->globalObject()->sharedArrayBuffer());
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
Value arguments[] = { Value(newLen) };
|
||||
Object* newValue = Object::construct(state, constructor, 1, arguments).toObject(state);
|
||||
if (!newValue->isSharedArrayBufferObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().SharedArrayBuffer.string(), true, state.context()->staticStrings().slice.string(), "%s: return value of constructor SharedArrayBuffer is not valid SharedArrayBuffer");
|
||||
Value newValue = Object::construct(state, constructor, 1, arguments);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (!newValue.toObject(state)->isSharedArrayBufferObject()) {
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().SharedArrayBuffer.string(), true, state.context()->staticStrings().slice.string(), "%s: return value of constructor SharedArrayBuffer is not valid SharedArrayBuffer");
|
||||
}
|
||||
|
||||
SharedArrayBufferObject* newBuffer = newValue->asSharedArrayBufferObject();
|
||||
SharedArrayBufferObject* newBuffer = newValue.toObject(state)->asSharedArrayBufferObject();
|
||||
if ((newBuffer->data() == O->data()) || (newBuffer->byteLength() < newLen)) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().SharedArrayBuffer.string(), true, state.context()->staticStrings().slice.string(), "%s: return value of constructor SharedArrayBuffer is not valid SharedArrayBuffer");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().SharedArrayBuffer.string(), true, state.context()->staticStrings().slice.string(), "%s: return value of constructor SharedArrayBuffer is not valid SharedArrayBuffer");
|
||||
}
|
||||
|
||||
newBuffer->fillData(O->data() + first, newLen);
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ static Value builtinStringConstructor(ExecutionState& state, Value thisValue, si
|
|||
return value.asSymbol()->symbolDescriptiveString();
|
||||
} else {
|
||||
s = value.toString(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
}
|
||||
}
|
||||
if (!newTarget.hasValue()) {
|
||||
|
|
@ -56,6 +57,7 @@ static Value builtinStringConstructor(ExecutionState& state, Value thisValue, si
|
|||
Object* proto = Object::getPrototypeFromConstructor(state, newTarget.value(), [](ExecutionState& state, Context* constructorRealm) -> Object* {
|
||||
return constructorRealm->globalObject()->stringPrototype();
|
||||
});
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
return new StringObject(state, proto, s);
|
||||
}
|
||||
|
||||
|
|
@ -68,7 +70,7 @@ static Value builtinStringToString(ExecutionState& state, Value thisValue, size_
|
|||
if (thisValue.isString())
|
||||
return thisValue.toString(state);
|
||||
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().String.string(), true, state.context()->staticStrings().toString.string(), ErrorObject::Messages::GlobalObject_ThisNotString);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().String.string(), true, state.context()->staticStrings().toString.string(), ErrorObject::Messages::GlobalObject_ThisNotString);
|
||||
RELEASE_ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
|
|
@ -76,6 +78,7 @@ static Value builtinStringIndexOf(ExecutionState& state, Value thisValue, size_t
|
|||
{
|
||||
RESOLVE_THIS_BINDING_TO_STRING(str, String, indexOf);
|
||||
String* searchStr = argv[0].toString(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
Value val;
|
||||
if (argc > 1) {
|
||||
|
|
@ -108,10 +111,12 @@ static Value builtinStringLastIndexOf(ExecutionState& state, Value thisValue, si
|
|||
// Let S be ToString(O).
|
||||
RESOLVE_THIS_BINDING_TO_STRING(S, String, lastIndexOf);
|
||||
String* searchStr = argv[0].toString(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
double numPos;
|
||||
if (argc > 1) {
|
||||
numPos = argv[1].toNumber(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
} else {
|
||||
numPos = Value().toNumber(state);
|
||||
}
|
||||
|
|
@ -137,6 +142,7 @@ static Value builtinStringLocaleCompare(ExecutionState& state, Value thisValue,
|
|||
RESOLVE_THIS_BINDING_TO_STRING(S, String, localeCompare);
|
||||
#if defined(ENABLE_ICU) && defined(ENABLE_INTL)
|
||||
String* That = argv[0].toString(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
Value locales, options;
|
||||
|
||||
if (argc >= 2) {
|
||||
|
|
@ -151,6 +157,7 @@ static Value builtinStringLocaleCompare(ExecutionState& state, Value thisValue,
|
|||
return Value(IntlCollator::compare(state, collator, S, That));
|
||||
#else
|
||||
String* That = argv[0].toString(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
return Value(stringCompare(*S, *That));
|
||||
#endif
|
||||
}
|
||||
|
|
@ -163,8 +170,10 @@ static Value builtinStringSubstring(ExecutionState& state, Value thisValue, size
|
|||
} else {
|
||||
size_t len = str->length();
|
||||
double doubleStart = argv[0].toNumber(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
Value end = argv[1];
|
||||
double doubleEnd = (argc < 2 || end.isUndefined()) ? len : end.toNumber(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
doubleStart = (std::isnan(doubleStart)) ? 0 : doubleStart;
|
||||
doubleEnd = (std::isnan(doubleEnd)) ? 0 : doubleEnd;
|
||||
|
||||
|
|
@ -184,12 +193,13 @@ static Value builtinStringSubstring(ExecutionState& state, Value thisValue, size
|
|||
static Value builtinStringMatch(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (thisValue.isUndefinedOrNull()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().String.string(), true, state.context()->staticStrings().match.string(), ErrorObject::Messages::GlobalObject_ThisUndefinedOrNull);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().String.string(), true, state.context()->staticStrings().match.string(), ErrorObject::Messages::GlobalObject_ThisUndefinedOrNull);
|
||||
}
|
||||
|
||||
Value regexp = argv[0];
|
||||
if (!regexp.isUndefinedOrNull()) {
|
||||
Value matcher = Object::getMethod(state, regexp, ObjectPropertyName(state.context()->vmInstance()->globalSymbols().match));
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (!matcher.isUndefined()) {
|
||||
Value args[1] = { thisValue };
|
||||
return Object::call(state, matcher, regexp, 1, args);
|
||||
|
|
@ -197,8 +207,12 @@ static Value builtinStringMatch(ExecutionState& state, Value thisValue, size_t a
|
|||
}
|
||||
|
||||
String* S = thisValue.toString(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
RegExpObject* rx = new RegExpObject(state, regexp.isUndefined() ? String::emptyString : regexp.toString(state), String::emptyString);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
Value func = rx->get(state, ObjectPropertyName(state.context()->vmInstance()->globalSymbols().match)).value(state, rx);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
Value args[1] = { Value(S) };
|
||||
return Object::call(state, func, rx, 1, args);
|
||||
}
|
||||
|
|
@ -206,28 +220,34 @@ static Value builtinStringMatch(ExecutionState& state, Value thisValue, size_t a
|
|||
static Value builtinStringMatchAll(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (thisValue.isUndefinedOrNull()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().String.string(), true, state.context()->staticStrings().match.string(), ErrorObject::Messages::GlobalObject_ThisUndefinedOrNull);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().String.string(), true, state.context()->staticStrings().match.string(), ErrorObject::Messages::GlobalObject_ThisUndefinedOrNull);
|
||||
}
|
||||
|
||||
Value regexp = argv[0];
|
||||
if (!regexp.isUndefinedOrNull()) {
|
||||
if (regexp.isObject() && regexp.asObject()->isRegExpObject()) {
|
||||
String* flags = regexp.asObject()->get(state, ObjectPropertyName(state, state.context()->staticStrings().flags)).value(state, regexp).toString(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (flags->find("g") == SIZE_MAX) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().String.string(), true, state.context()->staticStrings().match.string(), ErrorObject::Messages::GlobalObject_ThisUndefinedOrNull);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().String.string(), true, state.context()->staticStrings().match.string(), ErrorObject::Messages::GlobalObject_ThisUndefinedOrNull);
|
||||
}
|
||||
}
|
||||
Value matcher = Object::getMethod(state, regexp, ObjectPropertyName(state.context()->vmInstance()->globalSymbols().matchAll));
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (!matcher.isUndefined()) {
|
||||
Value args[1] = { thisValue };
|
||||
return Object::call(state, matcher, regexp, 1, args);
|
||||
}
|
||||
}
|
||||
String* S = thisValue.toString(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
StringBuilder builder;
|
||||
builder.appendChar('g');
|
||||
RegExpObject* rx = new RegExpObject(state, regexp.isUndefined() ? String::emptyString : regexp.toString(state), builder.finalize());
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
Value func = rx->get(state, ObjectPropertyName(state.context()->vmInstance()->globalSymbols().matchAll)).value(state, rx);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
Value args[1] = { Value(S) };
|
||||
return Object::call(state, func, rx, 1, args);
|
||||
}
|
||||
|
|
@ -250,6 +270,7 @@ static Value builtinStringNormalize(ExecutionState& state, Value thisValue, size
|
|||
NormalizationForm form = NFC;
|
||||
if (LIKELY(!argument.isUndefined())) {
|
||||
String* formString = argument.toString(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (formString->equals("NFC")) {
|
||||
form = NFC;
|
||||
} else if (formString->equals("NFD")) {
|
||||
|
|
@ -259,7 +280,7 @@ static Value builtinStringNormalize(ExecutionState& state, Value thisValue, size
|
|||
} else if (formString->equals("NFKD")) {
|
||||
form = NFKD;
|
||||
} else {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, "invalid normalization form");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::RangeError, "invalid normalization form");
|
||||
return Value();
|
||||
}
|
||||
}
|
||||
|
|
@ -287,14 +308,14 @@ static Value builtinStringNormalize(ExecutionState& state, Value thisValue, size
|
|||
break;
|
||||
}
|
||||
if (!normalizer || U_FAILURE(status)) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "normalization fails");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "normalization fails");
|
||||
return Value();
|
||||
}
|
||||
int32_t normalizedStringLength = unorm2_normalize(normalizer, (const UChar*)utf16Str.data(), utf16Str.length(), nullptr, 0, &status);
|
||||
|
||||
if (U_FAILURE(status) && status != U_BUFFER_OVERFLOW_ERROR) {
|
||||
// when normalize fails.
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "normalization fails");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "normalization fails");
|
||||
return Value();
|
||||
}
|
||||
UTF16StringData ret;
|
||||
|
|
@ -303,7 +324,7 @@ static Value builtinStringNormalize(ExecutionState& state, Value thisValue, size
|
|||
unorm2_normalize(normalizer, (const UChar*)utf16Str.data(), utf16Str.length(), (UChar*)ret.data(), normalizedStringLength, &status);
|
||||
|
||||
if (U_FAILURE(status)) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "normalization fails");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "normalization fails");
|
||||
return Value();
|
||||
}
|
||||
return new UTF16String(std::move(ret));
|
||||
|
|
@ -318,7 +339,7 @@ static Value builtinStringRepeat(ExecutionState& state, Value thisValue, size_t
|
|||
double count = argument.toInteger(state);
|
||||
double newStringLength = str->length() * count;
|
||||
if (count < 0 || count == std::numeric_limits<double>::infinity() || newStringLength > STRING_MAXIMUM_LENGTH) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, "invalid count number of String repeat method");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::RangeError, "invalid count number of String repeat method");
|
||||
}
|
||||
|
||||
if (newStringLength == 0) {
|
||||
|
|
@ -423,7 +444,7 @@ static Value stringReplaceFastPathHelper(ExecutionState& state, String* string,
|
|||
static Value builtinStringReplace(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (thisValue.isUndefinedOrNull()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().object.string(), true, state.context()->staticStrings().replace.string(), ErrorObject::Messages::GlobalObject_ThisUndefinedOrNull);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().object.string(), true, state.context()->staticStrings().replace.string(), ErrorObject::Messages::GlobalObject_ThisUndefinedOrNull);
|
||||
}
|
||||
|
||||
Value searchValue = argv[0];
|
||||
|
|
@ -434,6 +455,7 @@ static Value builtinStringReplace(ExecutionState& state, Value thisValue, size_t
|
|||
bool canUseFastPath = searchValue.isString() || (isSearchValueRegExp && searchValue.asPointerValue()->asRegExpObject()->yarrPatern()->m_captureGroupNames.size() == 0);
|
||||
if (!searchValue.isUndefinedOrNull()) {
|
||||
Value replacer = Object::getMethod(state, searchValue, ObjectPropertyName(state.context()->vmInstance()->globalSymbols().replace));
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (canUseFastPath && isSearchValueRegExp && replacer.isPointerValue() && replacer.asPointerValue() == state.context()->globalObject()->regexpReplaceMethod()) {
|
||||
auto exec = searchValue.asObject()->get(state, ObjectPropertyName(state.context()->staticStrings().exec));
|
||||
if (!exec.hasValue() || exec.value(state, searchValue) != state.context()->globalObject()->regexpExecMethod()) {
|
||||
|
|
@ -451,7 +473,9 @@ static Value builtinStringReplace(ExecutionState& state, Value thisValue, size_t
|
|||
}
|
||||
|
||||
String* string = thisValue.toString(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
String* searchString = searchValue.toString(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
bool functionalReplace = replaceValue.isCallable();
|
||||
|
||||
if (canUseFastPath) {
|
||||
|
|
@ -471,6 +495,7 @@ static Value builtinStringReplace(ExecutionState& state, Value thisValue, size_t
|
|||
regexp->createRegexMatchResult(state, string, result);
|
||||
}
|
||||
}
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
} else {
|
||||
size_t idx = string->find(searchString);
|
||||
if (idx != (size_t)-1) {
|
||||
|
|
@ -486,6 +511,7 @@ static Value builtinStringReplace(ExecutionState& state, Value thisValue, size_t
|
|||
// NOTE: replaceValue.toString should be called after searchValue.toString
|
||||
if (!functionalReplace) {
|
||||
replaceString = replaceValue.toString(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
}
|
||||
|
||||
// If no occurrences of searchString were found, return string.
|
||||
|
|
@ -516,7 +542,10 @@ static Value builtinStringReplace(ExecutionState& state, Value thisValue, size_t
|
|||
arguments[subLen] = Value((int)result.m_matchResults[i][0].m_start);
|
||||
arguments[subLen + 1] = string;
|
||||
// 21.1.3.14 (11) it should be called with this as undefined
|
||||
String* res = Object::call(state, callee, Value(), subLen + 2, arguments).toString(state);
|
||||
Value val = Object::call(state, callee, Value(), subLen + 2, arguments);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
String* res = val.toString(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
builer.appendSubString(res, 0, res->length());
|
||||
|
||||
if (i < matchCount - 1) {
|
||||
|
|
@ -531,6 +560,7 @@ static Value builtinStringReplace(ExecutionState& state, Value thisValue, size_t
|
|||
} else {
|
||||
if (!functionalReplace) {
|
||||
replaceValue = replaceValue.toString(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
}
|
||||
size_t pos = string->find(searchString, 0);
|
||||
String* matched = searchString;
|
||||
|
|
@ -543,10 +573,13 @@ static Value builtinStringReplace(ExecutionState& state, Value thisValue, size_t
|
|||
if (functionalReplace) {
|
||||
Value parameters[3] = { Value(matched), Value(pos), Value(string) };
|
||||
Value replValue = Object::call(state, replaceValue, Value(), 3, parameters);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
replStr = replValue.toString(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
} else {
|
||||
StringVector captures;
|
||||
replStr = String::getSubstitution(state, matched, string, pos, captures, Value(), replaceValue.toString(state));
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
}
|
||||
size_t tailpos = pos + matched->length();
|
||||
StringBuilder builder;
|
||||
|
|
@ -561,7 +594,7 @@ static Value builtinStringReplace(ExecutionState& state, Value thisValue, size_t
|
|||
static Value builtinStringReplaceAll(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (thisValue.isUndefinedOrNull()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().object.string(), true, state.context()->staticStrings().replaceAll.string(), ErrorObject::Messages::GlobalObject_ThisUndefinedOrNull);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().object.string(), true, state.context()->staticStrings().replaceAll.string(), ErrorObject::Messages::GlobalObject_ThisUndefinedOrNull);
|
||||
}
|
||||
Value searchValue = argv[0];
|
||||
Value replaceValue = argv[1];
|
||||
|
|
@ -570,12 +603,14 @@ static Value builtinStringReplaceAll(ExecutionState& state, Value thisValue, siz
|
|||
// If isRegExp is true, then
|
||||
if (searchValue.isObject() && searchValue.asObject()->isRegExp(state)) {
|
||||
Value flags = searchValue.asObject()->get(state, ObjectPropertyName(state, state.context()->staticStrings().flags)).value(state, searchValue);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (flags.isUndefinedOrNull() || !flags.toString(state)->contains("g")) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().replaceAll.string(), true, state.context()->staticStrings().replaceAll.string(), ErrorObject::Messages::GlobalObject_IllegalFirstArgument);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().replaceAll.string(), true, state.context()->staticStrings().replaceAll.string(), ErrorObject::Messages::GlobalObject_IllegalFirstArgument);
|
||||
}
|
||||
}
|
||||
// Let replacer be ? GetMethod(searchValue, @@replace).
|
||||
Value replacer = Object::getMethod(state, searchValue, ObjectPropertyName(state.context()->vmInstance()->globalSymbols().replace));
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (!replacer.isUndefined()) {
|
||||
Value args[2] = { thisValue, replaceValue };
|
||||
// Return ? Call(replacer, searchValue, « O, replaceValue »).
|
||||
|
|
@ -584,12 +619,15 @@ static Value builtinStringReplaceAll(ExecutionState& state, Value thisValue, siz
|
|||
}
|
||||
|
||||
String* string = thisValue.toString(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
String* searchString = searchValue.toString(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
bool functionalReplace = replaceValue.isCallable();
|
||||
// If functionalReplace is false, then
|
||||
if (!functionalReplace) {
|
||||
replaceValue = replaceValue.toString(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
}
|
||||
|
||||
size_t searchLength = searchString->length();
|
||||
|
|
@ -614,7 +652,10 @@ static Value builtinStringReplaceAll(ExecutionState& state, Value thisValue, siz
|
|||
// If functionalReplace is true, then
|
||||
if (functionalReplace) {
|
||||
Value args[3] = { searchString, Value(p), string };
|
||||
replacement = Object::call(state, replaceValue, Value(), 3, args).toString(state);
|
||||
Value rep = Object::call(state, replaceValue, Value(), 3, args);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
replacement = rep.toString(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
} else {
|
||||
StringVector captures;
|
||||
replacement = String::getSubstitution(state, searchString, string, p, captures, Value(), replaceValue.asString());
|
||||
|
|
@ -632,12 +673,13 @@ static Value builtinStringReplaceAll(ExecutionState& state, Value thisValue, siz
|
|||
static Value builtinStringSearch(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (thisValue.isUndefinedOrNull()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().String.string(), true, state.context()->staticStrings().search.string(), ErrorObject::Messages::GlobalObject_ThisUndefinedOrNull);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().String.string(), true, state.context()->staticStrings().search.string(), ErrorObject::Messages::GlobalObject_ThisUndefinedOrNull);
|
||||
}
|
||||
|
||||
Value regexp = argv[0];
|
||||
if (!regexp.isUndefinedOrNull()) {
|
||||
Value searcher = Object::getMethod(state, regexp, ObjectPropertyName(state.context()->vmInstance()->globalSymbols().search));
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (!searcher.isUndefined()) {
|
||||
Value args[1] = { thisValue };
|
||||
return Object::call(state, searcher, regexp, 1, args);
|
||||
|
|
@ -645,8 +687,12 @@ static Value builtinStringSearch(ExecutionState& state, Value thisValue, size_t
|
|||
}
|
||||
|
||||
String* string = thisValue.toString(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
RegExpObject* rx = new RegExpObject(state, regexp.isUndefined() ? String::emptyString : regexp.toString(state), String::emptyString);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
Value func = rx->get(state, ObjectPropertyName(state.context()->vmInstance()->globalSymbols().search)).value(state, rx);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
Value args[1] = { Value(string) };
|
||||
return Object::call(state, func, rx, 1, args);
|
||||
}
|
||||
|
|
@ -654,7 +700,7 @@ static Value builtinStringSearch(ExecutionState& state, Value thisValue, size_t
|
|||
static Value builtinStringSplit(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (thisValue.isUndefinedOrNull()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().String.string(), true, state.context()->staticStrings().split.string(), ErrorObject::Messages::GlobalObject_ThisUndefinedOrNull);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().String.string(), true, state.context()->staticStrings().split.string(), ErrorObject::Messages::GlobalObject_ThisUndefinedOrNull);
|
||||
}
|
||||
|
||||
Value separator = argv[0];
|
||||
|
|
@ -665,6 +711,7 @@ static Value builtinStringSplit(ExecutionState& state, Value thisValue, size_t a
|
|||
if (!separator.isUndefinedOrNull()) {
|
||||
// Let splitter be GetMethod(separator, @@split).
|
||||
Value splitter = Object::getMethod(state, separator, ObjectPropertyName(state.context()->vmInstance()->globalSymbols().split));
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// --- Optmize path
|
||||
// if splitter is builtin RegExp.prototype.split and separator is RegExpObject
|
||||
|
|
@ -680,6 +727,7 @@ static Value builtinStringSplit(ExecutionState& state, Value thisValue, size_t a
|
|||
|
||||
// Let S be ? ToString(O).
|
||||
String* S = thisValue.toString(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Let A be ! ArrayCreate(0).
|
||||
ArrayObject* A = new ArrayObject(state);
|
||||
// Let lengthA = 0.
|
||||
|
|
@ -695,6 +743,7 @@ static Value builtinStringSplit(ExecutionState& state, Value thisValue, size_t a
|
|||
P = separator.asPointerValue()->asRegExpObject();
|
||||
} else {
|
||||
P = separator.toString(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
}
|
||||
|
||||
// If lim = 0, return A.
|
||||
|
|
@ -723,6 +772,7 @@ static Value builtinStringSplit(ExecutionState& state, Value thisValue, size_t a
|
|||
if (P->isRegExpObject()) {
|
||||
RegexMatchResult result;
|
||||
ret = P->asRegExpObject()->matchNonGlobally(state, S, result, false, 0);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
} else {
|
||||
Value z = splitMatchUsingStr(S, 0, P->asString());
|
||||
if (z.isBoolean()) {
|
||||
|
|
@ -763,6 +813,7 @@ static Value builtinStringSplit(ExecutionState& state, Value thisValue, size_t a
|
|||
return A;
|
||||
q = p;
|
||||
}
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
}
|
||||
} else {
|
||||
String* R = P->asString();
|
||||
|
|
@ -870,10 +921,11 @@ static Value builtinStringFromCodePoint(ExecutionState& state, Value thisValue,
|
|||
for (size_t nextIndex = 0; nextIndex < argc; nextIndex++) {
|
||||
Value next = argv[nextIndex];
|
||||
double nextCP = next.toNumber(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
double toIntegerNexCP = next.toInteger(state);
|
||||
|
||||
if (nextCP != toIntegerNexCP || nextCP < 0 || nextCP > 0x10FFFF) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, "invalid code point");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::RangeError, "invalid code point");
|
||||
}
|
||||
|
||||
uint32_t cp = (uint32_t)nextCP;
|
||||
|
|
@ -897,6 +949,7 @@ static Value builtinStringConcat(ExecutionState& state, Value thisValue, size_t
|
|||
RESOLVE_THIS_BINDING_TO_STRING(str, String, concat);
|
||||
for (size_t i = 0; i < argc; i++) {
|
||||
String* appendStr = argv[i].toString(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
str = RopeString::createRopeString(str, appendStr, &state);
|
||||
}
|
||||
return Value(str);
|
||||
|
|
@ -1155,7 +1208,7 @@ static Value builtinStringValueOf(ExecutionState& state, Value thisValue, size_t
|
|||
} else if (thisValue.isObject() && thisValue.asObject()->isStringObject()) {
|
||||
return Value(thisValue.asPointerValue()->asStringObject()->primitiveValue());
|
||||
}
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ThisNotString);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ThisNotString);
|
||||
RELEASE_ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
|
|
@ -1169,10 +1222,11 @@ static Value builtinStringStartsWith(ExecutionState& state, Value thisValue, siz
|
|||
// If isRegExp is true, throw a TypeError exception.
|
||||
|
||||
if (searchString.isObject() && searchString.asObject()->isRegExp(state)) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "can't use RegExp with startsWith");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "can't use RegExp with startsWith");
|
||||
}
|
||||
// Let searchStr be ? ToString(searchString).
|
||||
String* searchStr = searchString.toString(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Let pos be ? ToInteger(position). (If position is undefined, this step produces the value 0.)
|
||||
double pos = 0;
|
||||
if (argc >= 2) {
|
||||
|
|
@ -1212,13 +1266,14 @@ static Value builtinStringEndsWith(ExecutionState& state, Value thisValue, size_
|
|||
// Let isRegExp be ? IsRegExp(searchString).
|
||||
// If isRegExp is true, throw a TypeError exception.
|
||||
if (searchString.isObject() && searchString.asObject()->isRegExp(state)) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "can't use RegExp with endsWith");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "can't use RegExp with endsWith");
|
||||
}
|
||||
// Let len be the number of elements in S.
|
||||
double len = S->length();
|
||||
|
||||
// Let searchStr be ? ToString(searchString).
|
||||
String* searchStr = searchString.toString(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// If endPosition is undefined, let pos be len, else let pos be ? ToInteger(endPosition).
|
||||
double pos = 0;
|
||||
if (argc >= 2 && !argv[1].isUndefined()) {
|
||||
|
|
@ -1266,8 +1321,10 @@ static Value builtinStringRaw(ExecutionState& state, Value thisValue, size_t arg
|
|||
Object* cooked = argTemplate.toObject(state);
|
||||
// Let raw be ? ToObject(? Get(cooked, "raw")).
|
||||
Object* raw = cooked->get(state, ObjectPropertyName(state.context()->staticStrings().raw)).value(state, cooked).toObject(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Let literalSegments be ? ToLength(? Get(raw, "length")).
|
||||
double literalSegments = raw->length(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// If literalSegments ≤ 0, return the empty string.
|
||||
if (literalSegments <= 0) {
|
||||
return String::emptyString;
|
||||
|
|
@ -1281,6 +1338,7 @@ static Value builtinStringRaw(ExecutionState& state, Value thisValue, size_t arg
|
|||
// Let nextKey be ! ToString(nextIndex).
|
||||
// Let nextSeg be ? ToString(? Get(raw, nextKey)).
|
||||
String* nextSeg = raw->get(state, ObjectPropertyName(state, Value(nextIndex))).value(state, raw).toString(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Append in order the code unit elements of nextSeg to the end of stringElements.
|
||||
for (size_t i = 0; i < nextSeg->length(); i++) {
|
||||
stringElements.appendChar(nextSeg->charAt(i));
|
||||
|
|
@ -1300,6 +1358,7 @@ static Value builtinStringRaw(ExecutionState& state, Value thisValue, size_t arg
|
|||
}
|
||||
// Let nextSub be ? ToString(next).
|
||||
String* nextSub = next.toString(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Append in order the code unit elements of nextSub to the end of stringElements.
|
||||
stringElements.appendString(nextSub);
|
||||
// Let nextIndex be nextIndex + 1.
|
||||
|
|
@ -1327,6 +1386,7 @@ static Value stringPad(ExecutionState& state, String* S, size_t argc, Value* arg
|
|||
String* filler;
|
||||
if (argc >= 2 && (!argv[1].isUndefined())) {
|
||||
filler = argv[1].toString(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
} else {
|
||||
filler = state.context()->staticStrings().asciiTable[0x20].string();
|
||||
}
|
||||
|
|
@ -1388,9 +1448,10 @@ static String* createHTML(ExecutionState& state, Value string, String* tag, Stri
|
|||
// Let S be ToString(str).
|
||||
// ReturnIfAbrupt(S).
|
||||
if (string.isUndefinedOrNull()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().String.string(), true, methodName.string(), ErrorObject::Messages::GlobalObject_ThisUndefinedOrNull);
|
||||
THROW_BUILTIN_ERROR_RETURN_NULL(state, ErrorCode::TypeError, state.context()->staticStrings().String.string(), true, methodName.string(), ErrorObject::Messages::GlobalObject_ThisUndefinedOrNull);
|
||||
}
|
||||
String* S = string.toString(state);
|
||||
RETURN_NULL_IF_PENDING_EXCEPTION
|
||||
|
||||
// Let p1 be the String value that is the concatenation of "<" and tag.
|
||||
StringBuilder sb;
|
||||
|
|
@ -1401,6 +1462,7 @@ static String* createHTML(ExecutionState& state, Value string, String* tag, Stri
|
|||
if (attribute->length()) {
|
||||
// Let V be ToString(value).
|
||||
String* V = value.toString(state);
|
||||
RETURN_NULL_IF_PENDING_EXCEPTION
|
||||
// ReturnIfAbrupt(V).
|
||||
// Let escapedV be the String value that is the same as V except that each occurrence of the code unit 0x0022 (QUOTATION MARK) in V has been replaced with the six code unit sequence """.
|
||||
StringBuilder sb;
|
||||
|
|
@ -1489,7 +1551,10 @@ static Value builtinStringAt(ExecutionState& state, Value thisValue, size_t argc
|
|||
#define DEFINE_STRING_ADDITIONAL_HTML_FUNCTION(fnName, P0, P1, P2) \
|
||||
static Value builtinString##fnName(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget) \
|
||||
{ \
|
||||
return createHTML(state, thisValue, P0, P1, P2, state.context()->staticStrings().fnName); \
|
||||
Value result = createHTML(state, thisValue, P0, P1, P2, state.context()->staticStrings().fnName); \
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION \
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION \
|
||||
return result; \
|
||||
}
|
||||
|
||||
// String.prototype.anchor (name)
|
||||
|
|
@ -1543,11 +1608,12 @@ static Value builtinStringIncludes(ExecutionState& state, Value thisValue, size_
|
|||
// If isRegExp is true, throw a TypeError exception.
|
||||
Value searchString = argv[0];
|
||||
if (searchString.isObject() && searchString.asObject()->isRegExp(state)) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "can't use RegExp with includes");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "can't use RegExp with includes");
|
||||
}
|
||||
|
||||
// Let searchStr be ? ToString(searchString).
|
||||
String* searchStr = searchString.toString(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// Let pos be ? ToInteger(position). (If position is undefined, this step produces the value 0.)
|
||||
double pos = 0;
|
||||
|
|
@ -1572,7 +1638,7 @@ static Value builtinStringIncludes(ExecutionState& state, Value thisValue, size_
|
|||
static Value builtinStringIteratorNext(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (!thisValue.isObject() || !thisValue.asObject()->isStringIteratorObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().StringIterator.string(), true, state.context()->staticStrings().next.string(), ErrorObject::Messages::GlobalObject_CalledOnIncompatibleReceiver);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().StringIterator.string(), true, state.context()->staticStrings().next.string(), ErrorObject::Messages::GlobalObject_CalledOnIncompatibleReceiver);
|
||||
}
|
||||
StringIteratorObject* iter = thisValue.asObject()->asIteratorObject()->asStringIteratorObject();
|
||||
return iter->next(state);
|
||||
|
|
|
|||
|
|
@ -31,29 +31,30 @@ static Value builtinSymbolConstructor(ExecutionState& state, Value thisValue, si
|
|||
{
|
||||
// If NewTarget is not undefined, throw a TypeError exception.
|
||||
if (newTarget.hasValue()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "illegal constructor Symbol");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "illegal constructor Symbol");
|
||||
}
|
||||
Optional<String*> descString = nullptr;
|
||||
// If description is undefined, let descString be undefined.
|
||||
if (!(argc == 0 || argv[0].isUndefined())) {
|
||||
// Else, let descString be ? ToString(description).
|
||||
descString = argv[0].toString(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
}
|
||||
// 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, ErrorCode::TypeError, state.context()->staticStrings().OBJ.string(), true, state.context()->staticStrings().BUILT_IN_METHOD.string(), ErrorObject::Messages::GlobalObject_CalledOnIncompatibleReceiver); \
|
||||
} \
|
||||
NAME = thisValue.asObject()->asSymbolObject()->primitiveValue(); \
|
||||
} else if (thisValue.isSymbol()) { \
|
||||
NAME = thisValue.asSymbol(); \
|
||||
} else { \
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().OBJ.string(), true, state.context()->staticStrings().BUILT_IN_METHOD.string(), ErrorObject::Messages::GlobalObject_CalledOnIncompatibleReceiver); \
|
||||
#define RESOLVE_THIS_BINDING_TO_SYMBOL(NAME, OBJ, BUILT_IN_METHOD) \
|
||||
Symbol* NAME = nullptr; \
|
||||
if (thisValue.isObject()) { \
|
||||
if (!thisValue.asObject()->isSymbolObject()) { \
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().OBJ.string(), true, state.context()->staticStrings().BUILT_IN_METHOD.string(), ErrorObject::Messages::GlobalObject_CalledOnIncompatibleReceiver); \
|
||||
} \
|
||||
NAME = thisValue.asObject()->asSymbolObject()->primitiveValue(); \
|
||||
} else if (thisValue.isSymbol()) { \
|
||||
NAME = thisValue.asSymbol(); \
|
||||
} else { \
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().OBJ.string(), true, state.context()->staticStrings().BUILT_IN_METHOD.string(), ErrorObject::Messages::GlobalObject_CalledOnIncompatibleReceiver); \
|
||||
}
|
||||
|
||||
static Value builtinSymbolToString(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
|
|
@ -78,6 +79,7 @@ static Value builtinSymbolFor(ExecutionState& state, Value thisValue, size_t arg
|
|||
{
|
||||
// Let stringKey be ? ToString(key).
|
||||
String* stringKey = argv[0].toString(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
return Symbol::fromGlobalSymbolRegistry(state.context()->vmInstance(), stringKey);
|
||||
}
|
||||
|
||||
|
|
@ -85,7 +87,7 @@ static Value builtinSymbolKeyFor(ExecutionState& state, Value thisValue, size_t
|
|||
{
|
||||
// If Type(sym) is not Symbol, throw a TypeError exception.
|
||||
if (!argv[0].isSymbol()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_IllegalFirstArgument);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_IllegalFirstArgument);
|
||||
}
|
||||
Symbol* sym = argv[0].asSymbol();
|
||||
// For each element e of the GlobalSymbolRegistry List (see 19.4.2.1),
|
||||
|
|
@ -118,7 +120,7 @@ static Value builtinSymbolDescriptionGetter(ExecutionState& state, Value thisVal
|
|||
return thisValue.asObject()->asSymbolObject()->primitiveValue()->description().value();
|
||||
|
||||
} else {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "getter called on non-Symbol object");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "getter called on non-Symbol object");
|
||||
}
|
||||
return Value();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,60 +32,60 @@ namespace Escargot {
|
|||
#define CHECK_TEMPORAL_OBJECT_HAS_YEAR_AND_MONTH(temporalDateLike) \
|
||||
!(temporalDateLike.isObject() && (temporalDateLike.asObject()->isTemporalPlainDateObject() || temporalDateLike.asObject()->isTemporalPlainDateTimeObject() || temporalDateLike.asObject()->isTemporalPlainYearMonthObject()))
|
||||
|
||||
#define CHECK_TEMPORAL_PLAIN_YEAR_MONTH(state, value) \
|
||||
if (!(value.isObject() && value.asObject()->isTemporalPlainYearMonthObject())) { \
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Invalid type"); \
|
||||
#define CHECK_TEMPORAL_PLAIN_YEAR_MONTH(state, value) \
|
||||
if (!(value.isObject() && value.asObject()->isTemporalPlainYearMonthObject())) { \
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Invalid type"); \
|
||||
}
|
||||
|
||||
#define CHECK_TEMPORAL_INSTANT(state, value) \
|
||||
if (!(value.isObject() && value.asObject()->isTemporalInstantObject())) { \
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "wrong type"); \
|
||||
#define CHECK_TEMPORAL_INSTANT(state, value) \
|
||||
if (!(value.isObject() && value.asObject()->isTemporalInstantObject())) { \
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "wrong type"); \
|
||||
}
|
||||
|
||||
#define CHECK_TEMPORAL_CALENDAR(state, thisValue, argc) \
|
||||
if (!(thisValue.isObject() && thisValue.asObject()->isTemporalCalendarObject())) { \
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ThisNotObject); \
|
||||
} \
|
||||
\
|
||||
ASSERT(thisValue.asObject()->asTemporalCalendarObject()->getIdentifier()->equals("iso8601")); \
|
||||
\
|
||||
if (argc == 0) { \
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Invalid type"); \
|
||||
#define CHECK_TEMPORAL_CALENDAR(state, thisValue, argc) \
|
||||
if (!(thisValue.isObject() && thisValue.asObject()->isTemporalCalendarObject())) { \
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ThisNotObject); \
|
||||
} \
|
||||
\
|
||||
ASSERT(thisValue.asObject()->asTemporalCalendarObject()->getIdentifier()->equals("iso8601")); \
|
||||
\
|
||||
if (argc == 0) { \
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Invalid type"); \
|
||||
}
|
||||
|
||||
#define CHECK_TEMPORAL_ZONED_DATE_TIME(state, value) \
|
||||
if (!(value.isObject() && value.asObject()->isTemporalZonedDateTimeObject())) { \
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "wrong type"); \
|
||||
#define CHECK_TEMPORAL_ZONED_DATE_TIME(state, value) \
|
||||
if (!(value.isObject() && value.asObject()->isTemporalZonedDateTimeObject())) { \
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "wrong type"); \
|
||||
}
|
||||
|
||||
#define CHECK_TEMPORAL_PLAIN_DATE(state, value) \
|
||||
if (!(value.isObject() && value.asObject()->isTemporalPlainDateObject())) { \
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Invalid type"); \
|
||||
#define CHECK_TEMPORAL_PLAIN_DATE(state, value) \
|
||||
if (!(value.isObject() && value.asObject()->isTemporalPlainDateObject())) { \
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Invalid type"); \
|
||||
}
|
||||
|
||||
#define CHECK_TEMPORAL_PLAIN_TIME(state, value) \
|
||||
if (!(value.isObject() && value.asObject()->isTemporalPlainTimeObject())) { \
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Invalid type"); \
|
||||
#define CHECK_TEMPORAL_PLAIN_TIME(state, value) \
|
||||
if (!(value.isObject() && value.asObject()->isTemporalPlainTimeObject())) { \
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Invalid type"); \
|
||||
}
|
||||
|
||||
#define CHECK_TEMPORAL_PLAIN_DATE_TIME(state, value) \
|
||||
if (!(value.isObject() && value.asObject()->isTemporalPlainDateTimeObject())) { \
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Invalid type"); \
|
||||
#define CHECK_TEMPORAL_PLAIN_DATE_TIME(state, value) \
|
||||
if (!(value.isObject() && value.asObject()->isTemporalPlainDateTimeObject())) { \
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Invalid type"); \
|
||||
}
|
||||
|
||||
#define CHECK_TEMPORAL_DURATION(state, value) \
|
||||
if (!(value.isObject() && value.asObject()->isTemporalDurationObject())) { \
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Invalid type"); \
|
||||
#define CHECK_TEMPORAL_DURATION(state, value) \
|
||||
if (!(value.isObject() && value.asObject()->isTemporalDurationObject())) { \
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Invalid type"); \
|
||||
}
|
||||
|
||||
#define CHECK_TEMPORAL_TIME_ZONE(state, value) \
|
||||
if (!(value.isObject() && value.asObject()->isTemporalTimeZoneObject())) { \
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Invalid type"); \
|
||||
#define CHECK_TEMPORAL_TIME_ZONE(state, value) \
|
||||
if (!(value.isObject() && value.asObject()->isTemporalTimeZoneObject())) { \
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Invalid type"); \
|
||||
}
|
||||
|
||||
#define CHECK_TEMPORAL_TIME_ZONE_OFFSET_VALUE(state, value) \
|
||||
if (value.asObject()->asTemporalTimeZoneObject()->getIdentifier()->equals("UTC") && !value.asObject()->asTemporalTimeZoneObject()->getOffsetNanoseconds().isInt32()) { \
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Invalid offset value"); \
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Invalid offset value"); \
|
||||
}
|
||||
|
||||
static TemporalPlainDateObject* getTemporalPlainDate(ExecutionState& state, const Value& thisValue, unsigned long argc, Value* argv)
|
||||
|
|
@ -97,13 +97,13 @@ static TemporalPlainDateObject* getTemporalPlainDate(ExecutionState& state, cons
|
|||
static Value temporalInstantFromEpoch(ExecutionState& state, size_t argc, Value* argv, BigInt* epoch)
|
||||
{
|
||||
if (argc == 0) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_IllegalFirstArgument);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_IllegalFirstArgument);
|
||||
}
|
||||
|
||||
auto epochNanoSeconds = argv[0].toBigInt(state)->multiply(state, epoch);
|
||||
|
||||
if (!TemporalInstantObject::isValidEpochNanoseconds(epochNanoSeconds)) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, "nanoSeconds is out of range");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::RangeError, "nanoSeconds is out of range");
|
||||
}
|
||||
|
||||
return TemporalInstantObject::createTemporalInstant(state, epochNanoSeconds);
|
||||
|
|
@ -138,13 +138,13 @@ static Value builtinTemporalNowPlainDateTimeISO(ExecutionState& state, Value thi
|
|||
static Value builtinTemporalPlainDateConstructor(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (!newTarget.hasValue()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::New_Target_Is_Undefined);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::New_Target_Is_Undefined);
|
||||
}
|
||||
|
||||
ASSERT(argc > 2);
|
||||
|
||||
if (!(argv[0].isInteger(state) || argv[1].isInteger(state) || argv[2].isInteger(state))) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Invalid type");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Invalid type");
|
||||
}
|
||||
|
||||
Value calendar = TemporalCalendarObject::toTemporalCalendarWithISODefault(state, argc > 4 ? argv[3] : Value());
|
||||
|
|
@ -154,7 +154,7 @@ static Value builtinTemporalPlainDateConstructor(ExecutionState& state, Value th
|
|||
static Value builtinTemporalPlainDateFrom(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (argc > 1 && !argv[1].isObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "options must be object");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "options must be object");
|
||||
}
|
||||
|
||||
if (argv[0].isObject() && argv[0].asObject()->isTemporalPlainDateObject()) {
|
||||
|
|
@ -264,7 +264,7 @@ static Value builtinTemporalPlainDatePrototypeSubtract(ExecutionState& state, Va
|
|||
static Value builtinTemporalPlainTimeConstructor(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (!newTarget.hasValue()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::New_Target_Is_Undefined);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::New_Target_Is_Undefined);
|
||||
}
|
||||
|
||||
int values[6];
|
||||
|
|
@ -272,7 +272,7 @@ static Value builtinTemporalPlainTimeConstructor(ExecutionState& state, Value th
|
|||
|
||||
for (unsigned int i = 0; i < argc && i < 6; ++i) {
|
||||
if (!argv[i].isInteger(state)) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Invalid type");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Invalid type");
|
||||
}
|
||||
values[i] = argv[i].asInt32();
|
||||
}
|
||||
|
|
@ -365,7 +365,7 @@ static Value builtinTemporalPlainTimeWith(ExecutionState& state, Value thisValue
|
|||
TemporalPlainTimeObject* temporalTime = thisValue.asObject()->asTemporalPlainTimeObject();
|
||||
|
||||
if (!argv[0].isObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "temporalTimeLike is not an Object");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "temporalTimeLike is not an Object");
|
||||
}
|
||||
|
||||
Temporal::rejectObjectWithCalendarOrTimeZone(state, argv[0]);
|
||||
|
|
@ -423,13 +423,13 @@ static Value builtinTemporalPlainTimeEquals(ExecutionState& state, Value thisVal
|
|||
static Value builtinTemporalPlainDateTimeConstructor(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (!newTarget.hasValue()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::New_Target_Is_Undefined);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::New_Target_Is_Undefined);
|
||||
}
|
||||
|
||||
ASSERT(argc > 2);
|
||||
|
||||
if (!(argv[0].isInteger(state) || argv[1].isInteger(state) || argv[2].isInteger(state)) || !(argc > 3 && argv[3].isInteger(state)) || !(argc > 4 && argv[4].isInteger(state)) || !(argc > 5 && argv[5].isInteger(state)) || !(argc > 6 && argv[6].isInteger(state)) || !(argc > 7 && argv[7].isInteger(state)) || !(argc > 8 && argv[8].isInteger(state))) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Invalid type");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Invalid type");
|
||||
}
|
||||
|
||||
Value calendar = TemporalCalendarObject::toTemporalCalendarWithISODefault(state, argc > 8 ? argv[9] : Value());
|
||||
|
|
@ -439,7 +439,7 @@ static Value builtinTemporalPlainDateTimeConstructor(ExecutionState& state, Valu
|
|||
static Value builtinTemporalPlainDateTimeFrom(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (argc > 1 && !argv[1].isObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "options must be object");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "options must be object");
|
||||
}
|
||||
|
||||
if (argv[0].isObject() && argv[0].asObject()->isTemporalPlainDateTimeObject()) {
|
||||
|
|
@ -551,11 +551,11 @@ static Value builtinTemporalPlainDateTimePrototypeSubtract(ExecutionState& state
|
|||
static Value builtinTemporalZonedDateTimeConstructor(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (!argv[0].isBigInt()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Invalid type");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Invalid type");
|
||||
}
|
||||
|
||||
if (!TemporalInstantObject::isValidEpochNanoseconds(argv[0])) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, "epoch Nanoseconds is out of range");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::RangeError, "epoch Nanoseconds is out of range");
|
||||
}
|
||||
|
||||
auto timeZone = TemporalTimeZoneObject::toTemporalTimeZone(state, argv[1]).asObject()->asTemporalTimeZoneObject();
|
||||
|
|
@ -796,7 +796,7 @@ static Value builtinTemporalZonedDateTimePrototypeSubtract(ExecutionState& state
|
|||
static Value builtinTemporalDurationConstructor(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (!newTarget.hasValue()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::New_Target_Is_Undefined);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::New_Target_Is_Undefined);
|
||||
}
|
||||
|
||||
int values[10];
|
||||
|
|
@ -804,7 +804,7 @@ static Value builtinTemporalDurationConstructor(ExecutionState& state, Value thi
|
|||
|
||||
for (unsigned int i = 0; i < argc && i < 10; ++i) {
|
||||
if (!argv[i].isInteger(state)) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Invalid type");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Invalid type");
|
||||
}
|
||||
values[i] = argv[i].asInt32();
|
||||
}
|
||||
|
|
@ -815,7 +815,7 @@ static Value builtinTemporalDurationConstructor(ExecutionState& state, Value thi
|
|||
static Value builtinTemporalDurationFrom(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (argc == 0) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Invalid first argument");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Invalid first argument");
|
||||
}
|
||||
|
||||
if (argv[0].isObject() && argv[0].asObject()->isTemporalDurationObject()) {
|
||||
|
|
@ -931,14 +931,14 @@ static Value builtinTemporalDurationPrototypeSubtract(ExecutionState& state, Val
|
|||
static Value builtinTemporalPlainYearMonthConstructor(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (!newTarget.hasValue()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::New_Target_Is_Undefined);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::New_Target_Is_Undefined);
|
||||
}
|
||||
|
||||
int referenceISODay = 1;
|
||||
|
||||
if (argc >= 4) {
|
||||
if (argv[3].isInt32()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Invalid type");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Invalid type");
|
||||
}
|
||||
referenceISODay = argv[3].asInt32();
|
||||
}
|
||||
|
|
@ -1069,19 +1069,19 @@ static Value builtinTemporalPlainYearMonthPrototypeSubtract(ExecutionState& stat
|
|||
static Value builtinTemporalInstantConstructor(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (!newTarget.hasValue()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::New_Target_Is_Undefined);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::New_Target_Is_Undefined);
|
||||
}
|
||||
|
||||
if (argc == 0) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_IllegalFirstArgument);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_IllegalFirstArgument);
|
||||
}
|
||||
|
||||
if (!(argv[0].isBigInt() || argv[0].isString())) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Invalid type");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Invalid type");
|
||||
}
|
||||
|
||||
if (!TemporalInstantObject::isValidEpochNanoseconds(argv[0].toBigInt(state))) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, "Invalid epoch nanoseconds");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::RangeError, "Invalid epoch nanoseconds");
|
||||
}
|
||||
|
||||
return TemporalInstantObject::createTemporalInstant(state, argv[0].toBigInt(state), newTarget);
|
||||
|
|
@ -1090,7 +1090,7 @@ static Value builtinTemporalInstantConstructor(ExecutionState& state, Value this
|
|||
static Value builtinTemporalInstantFrom(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (argc == 0) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_IllegalFirstArgument);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_IllegalFirstArgument);
|
||||
}
|
||||
|
||||
if (argv[0].isObject() && argv[0].asObject()->isTemporalInstantObject()) {
|
||||
|
|
@ -1177,14 +1177,14 @@ static Value builtinTemporalInstantPrototypeSubtract(ExecutionState& state, Valu
|
|||
static Value builtinTemporalPlainMonthDayConstructor(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (!newTarget.hasValue()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::New_Target_Is_Undefined);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::New_Target_Is_Undefined);
|
||||
}
|
||||
|
||||
int referenceISOYear = 1972;
|
||||
|
||||
if (argc >= 4) {
|
||||
if (!argv[3].isInt32()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Invalid type");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Invalid type");
|
||||
}
|
||||
referenceISOYear = argv[3].asInt32();
|
||||
}
|
||||
|
|
@ -1222,11 +1222,11 @@ static Value builtinTemporalPlainMonthDayPrototypeDay(ExecutionState& state, Val
|
|||
static Value builtinTemporalTimeZoneConstructor(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (!newTarget.hasValue()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::New_Target_Is_Undefined);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::New_Target_Is_Undefined);
|
||||
}
|
||||
|
||||
if (!argv[0].isString()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, "Expected string");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::RangeError, "Expected string");
|
||||
}
|
||||
|
||||
std::string identifier(argv[0].asString()->toNonGCUTF8StringData());
|
||||
|
|
@ -1235,7 +1235,7 @@ static Value builtinTemporalTimeZoneConstructor(ExecutionState& state, Value thi
|
|||
|
||||
if (identifier.empty()) {
|
||||
if (!TemporalTimeZoneObject::isValidTimeZoneName(argv[0].asString()->toNonGCUTF8StringData())) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, "Invalid TimeZone identifier");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::RangeError, "Invalid TimeZone identifier");
|
||||
}
|
||||
identifier = TemporalTimeZoneObject::canonicalizeTimeZoneName(argv[0].asString()->toNonGCUTF8StringData());
|
||||
}
|
||||
|
|
@ -1306,7 +1306,7 @@ static Value builtinTemporalTimeZonePrototypeGetPossibleInstantsFor(ExecutionSta
|
|||
|
||||
for (auto& possibleEpochNanosecond : possibleEpochNanoseconds) {
|
||||
if (!TemporalInstantObject::isValidEpochNanoseconds(possibleEpochNanosecond)) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, "Invalid epoch nanosecond");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::RangeError, "Invalid epoch nanosecond");
|
||||
}
|
||||
possibleInstants.push_back(TemporalInstantObject::createTemporalInstant(state, possibleEpochNanosecond));
|
||||
}
|
||||
|
|
@ -1357,17 +1357,17 @@ static Value builtinTemporalTimeZonePrototypeGetPreviousTransition(ExecutionStat
|
|||
static Value builtinTemporalCalendarConstructor(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (!newTarget.hasValue()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::New_Target_Is_Undefined);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::New_Target_Is_Undefined);
|
||||
}
|
||||
|
||||
if (!argv[0].isString()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, "First argument is not string");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::RangeError, "First argument is not string");
|
||||
}
|
||||
|
||||
String* id = argv[0].asString();
|
||||
|
||||
if (!TemporalCalendarObject::isBuiltinCalendar(id)) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, ErrorObject::Messages::GlobalObject_RangeError);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::RangeError, ErrorObject::Messages::GlobalObject_RangeError);
|
||||
}
|
||||
|
||||
return TemporalCalendarObject::createTemporalCalendar(state, id, newTarget);
|
||||
|
|
@ -1381,7 +1381,7 @@ static Value builtinTemporalCalendarFrom(ExecutionState& state, Value thisValue,
|
|||
static Value builtinTemporalCalendarPrototypeId(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (!thisValue.isObject() || !thisValue.asObject()->isTemporalCalendarObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ThisNotObject);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ThisNotObject);
|
||||
}
|
||||
|
||||
return thisValue.asObject()->asTemporalCalendarObject()->getIdentifier();
|
||||
|
|
@ -1390,7 +1390,7 @@ static Value builtinTemporalCalendarPrototypeId(ExecutionState& state, Value thi
|
|||
static Value builtinTemporalCalendarPrototypeDateFromFields(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (argc > 1 && !argv[0].isObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "fields is not an object");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "fields is not an object");
|
||||
}
|
||||
|
||||
Object* options;
|
||||
|
|
@ -1539,6 +1539,7 @@ static Value builtinTemporalCalendarFields(ExecutionState& state, Value thisValu
|
|||
|
||||
while (true) {
|
||||
next = IteratorObject::iteratorStep(state, iteratorRecord);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
if (!next.hasValue()) {
|
||||
break;
|
||||
|
|
@ -1579,7 +1580,7 @@ static Value builtinTemporalCalendarFields(ExecutionState& state, Value thisValu
|
|||
static Value builtinTemporalCalendarPrototypeMergeFields(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (argc < 2) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Too few arguments");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Too few arguments");
|
||||
}
|
||||
|
||||
Value fields = argv[0];
|
||||
|
|
|
|||
|
|
@ -28,23 +28,27 @@
|
|||
|
||||
namespace Escargot {
|
||||
|
||||
#define RESOLVE_THIS_BINDING_TO_TYPEDARRAY(NAME, OBJ, BUILT_IN_METHOD) \
|
||||
if (UNLIKELY(!thisValue.isObject() || !thisValue.asObject()->isTypedArrayObject())) { \
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().OBJ.string(), true, state.context()->staticStrings().BUILT_IN_METHOD.string(), ErrorObject::Messages::GlobalObject_CalledOnIncompatibleReceiver); \
|
||||
} \
|
||||
#define RESOLVE_THIS_BINDING_TO_TYPEDARRAY(NAME, OBJ, BUILT_IN_METHOD) \
|
||||
if (UNLIKELY(!thisValue.isObject() || !thisValue.asObject()->isTypedArrayObject())) { \
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().OBJ.string(), true, state.context()->staticStrings().BUILT_IN_METHOD.string(), ErrorObject::Messages::GlobalObject_CalledOnIncompatibleReceiver); \
|
||||
} \
|
||||
TypedArrayObject* NAME = thisValue.asPointerValue()->asTypedArrayObject();
|
||||
|
||||
|
||||
// https://www.ecma-international.org/ecma-262/10.0/#typedarray-create
|
||||
static Object* createTypedArray(ExecutionState& state, const Value& constructor, size_t argc, Value* argv)
|
||||
{
|
||||
Object* newTypedArray = Object::construct(state, constructor, argc, argv).toObject(state);
|
||||
Value newTypedArrayValue = Object::construct(state, constructor, argc, argv);
|
||||
RETURN_NULL_IF_PENDING_EXCEPTION
|
||||
Object* newTypedArray = newTypedArrayValue.toObject(state);
|
||||
RETURN_NULL_IF_PENDING_EXCEPTION
|
||||
TypedArrayObject::validateTypedArray(state, newTypedArray);
|
||||
RETURN_NULL_IF_PENDING_EXCEPTION
|
||||
|
||||
if (argc == 1 && argv[0].isNumber()) {
|
||||
double arrayLength = newTypedArray->asTypedArrayObject()->arrayLength();
|
||||
if (arrayLength < argv[0].asNumber()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "invalid TypedArray length");
|
||||
THROW_BUILTIN_ERROR_RETURN_NULL(state, ErrorCode::TypeError, "invalid TypedArray length");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -89,17 +93,20 @@ static Value TypedArraySpeciesCreate(ExecutionState& state, TypedArrayObject* ex
|
|||
Value defaultConstructor = getDefaultTypedArrayConstructor(state, exemplar->typedArrayType());
|
||||
// Let C be SpeciesConstructor(O, defaultConstructor).
|
||||
Value C = exemplar->speciesConstructor(state, defaultConstructor);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
Value A = Object::construct(state, C, argc, argumentList);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
TypedArrayObject::validateTypedArray(state, A);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (argc == 1 && argumentList[0].isNumber() && A.asObject()->asTypedArrayObject()->arrayLength() < argumentList->toNumber(state)) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().TypedArray.string(), false, String::emptyString, ErrorObject::Messages::GlobalObject_InvalidArrayLength);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().TypedArray.string(), false, String::emptyString, ErrorObject::Messages::GlobalObject_InvalidArrayLength);
|
||||
}
|
||||
return A;
|
||||
}
|
||||
|
||||
static Value builtinTypedArrayConstructor(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::Not_Constructor);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::Not_Constructor);
|
||||
return Value();
|
||||
}
|
||||
|
||||
|
|
@ -110,7 +117,7 @@ static Value builtinTypedArrayFrom(ExecutionState& state, Value thisValue, size_
|
|||
Value source = argv[0];
|
||||
|
||||
if (!C.isConstructor()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().TypedArray.string(), false, String::emptyString, ErrorObject::Messages::GlobalObject_ThisNotConstructor);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().TypedArray.string(), false, String::emptyString, ErrorObject::Messages::GlobalObject_ThisNotConstructor);
|
||||
}
|
||||
|
||||
Value mapfn;
|
||||
|
|
@ -125,17 +132,20 @@ static Value builtinTypedArrayFrom(ExecutionState& state, Value thisValue, size_
|
|||
bool mapping = false;
|
||||
if (!mapfn.isUndefined()) {
|
||||
if (!mapfn.isCallable()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "mapfn is not callable");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "mapfn is not callable");
|
||||
}
|
||||
mapping = true;
|
||||
}
|
||||
|
||||
Value usingIterator = Object::getMethod(state, source, ObjectPropertyName(state.context()->vmInstance()->globalSymbols().iterator));
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (!usingIterator.isUndefined()) {
|
||||
ValueVectorWithInlineStorage values = IteratorObject::iterableToList(state, source, usingIterator);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
size_t len = values.size();
|
||||
Value arg[1] = { Value(len) };
|
||||
Object* targetObj = createTypedArray(state, C, 1, arg);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
size_t k = 0;
|
||||
while (k < len) {
|
||||
|
|
@ -143,8 +153,10 @@ static Value builtinTypedArrayFrom(ExecutionState& state, Value thisValue, size_
|
|||
if (mapping) {
|
||||
Value args[2] = { values[k], Value(k) };
|
||||
mappedValue = Object::call(state, mapfn, T, 2, args);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
}
|
||||
targetObj->setIndexedPropertyThrowsException(state, Value(k), mappedValue);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
k++;
|
||||
}
|
||||
|
||||
|
|
@ -152,22 +164,28 @@ static Value builtinTypedArrayFrom(ExecutionState& state, Value thisValue, size_
|
|||
}
|
||||
|
||||
Object* arrayLike = source.toObject(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
size_t len = arrayLike->length(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
Value arg[1] = { Value(len) };
|
||||
Object* targetObj = createTypedArray(state, C, 1, arg);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
size_t k = 0;
|
||||
while (k < len) {
|
||||
Value kValue = arrayLike->getIndexedProperty(state, Value(k)).value(state, arrayLike);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
Value mappedValue = kValue;
|
||||
if (mapping) {
|
||||
// Let mappedValue be Call(mapfn, T, «kValue, k»).
|
||||
Value args[2] = { kValue, Value(k) };
|
||||
mappedValue = Object::call(state, mapfn, T, 2, args);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
}
|
||||
// Let setStatus be Set(targetObj, Pk, mappedValue, true).
|
||||
targetObj->setIndexedPropertyThrowsException(state, Value(k), mappedValue);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
k++;
|
||||
}
|
||||
|
||||
|
|
@ -180,16 +198,18 @@ static Value builtinTypedArrayOf(ExecutionState& state, Value thisValue, size_t
|
|||
size_t len = argc;
|
||||
Value C = thisValue;
|
||||
if (!C.isConstructor()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().TypedArray.string(), false, String::emptyString, ErrorObject::Messages::GlobalObject_ThisNotConstructor);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().TypedArray.string(), false, String::emptyString, ErrorObject::Messages::GlobalObject_ThisNotConstructor);
|
||||
}
|
||||
|
||||
Value arg[1] = { Value(len) };
|
||||
Object* newObj = createTypedArray(state, C, 1, arg);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
size_t k = 0;
|
||||
while (k < len) {
|
||||
Value kValue = argv[k];
|
||||
newObj->setIndexedPropertyThrowsException(state, Value(k), kValue);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
k++;
|
||||
}
|
||||
return newObj;
|
||||
|
|
@ -236,6 +256,7 @@ static void initializeTypedArrayFromTypedArray(ExecutionState& state, TypedArray
|
|||
{
|
||||
ArrayBuffer* srcData = srcArray->buffer();
|
||||
srcData->throwTypeErrorIfDetached(state);
|
||||
RETURN_IF_PENDING_EXCEPTION
|
||||
|
||||
size_t elementLength = srcArray->arrayLength();
|
||||
size_t srcElementSize = srcArray->elementSize();
|
||||
|
|
@ -245,23 +266,29 @@ static void initializeTypedArrayFromTypedArray(ExecutionState& state, TypedArray
|
|||
|
||||
Value bufferConstructor;
|
||||
#if defined(ENABLE_THREADING)
|
||||
if (srcData->isSharedArrayBufferObject())
|
||||
if (srcData->isSharedArrayBufferObject()) {
|
||||
// Let bufferConstructor be %ArrayBuffer%.
|
||||
bufferConstructor = state.context()->globalObject()->arrayBuffer();
|
||||
else
|
||||
} else {
|
||||
#endif
|
||||
// Let bufferConstructor be ? SpeciesConstructor(srcData, %ArrayBuffer%).
|
||||
bufferConstructor = srcData->speciesConstructor(state, state.context()->globalObject()->arrayBuffer());
|
||||
RETURN_IF_PENDING_EXCEPTION
|
||||
}
|
||||
|
||||
|
||||
ArrayBufferObject* data = nullptr;
|
||||
if (obj->typedArrayType() == srcArray->typedArrayType()) {
|
||||
// Let data be ? CloneArrayBuffer(srcData, srcByteOffset, byteLength, bufferConstructor).
|
||||
data = ArrayBufferObject::cloneArrayBuffer(state, srcData, srcByteOffset, byteLength, bufferConstructor.asObject());
|
||||
RETURN_IF_PENDING_EXCEPTION
|
||||
} else {
|
||||
// Let data be AllocateArrayBuffer(bufferConstructor, byteLength).
|
||||
data = ArrayBufferObject::allocateArrayBuffer(state, bufferConstructor.asObject(), byteLength);
|
||||
RETURN_IF_PENDING_EXCEPTION
|
||||
// If IsDetachedBuffer(srcData) is true, throw a TypeError exception.
|
||||
srcData->throwTypeErrorIfDetached(state);
|
||||
RETURN_IF_PENDING_EXCEPTION
|
||||
|
||||
// Let srcByteIndex be srcByteOffset.
|
||||
size_t srcByteIndex = srcByteOffset;
|
||||
|
|
@ -294,31 +321,34 @@ static void initializeTypedArrayFromArrayBuffer(ExecutionState& state, TypedArra
|
|||
{
|
||||
size_t elementSize = obj->elementSize();
|
||||
uint64_t offset = byteOffset.toIndex(state);
|
||||
RETURN_IF_PENDING_EXCEPTION
|
||||
if (offset == Value::InvalidIndexValue || offset % elementSize != 0) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, state.context()->staticStrings().TypedArray.string(), false, String::emptyString, ErrorObject::Messages::GlobalObject_InvalidArrayBufferOffset);
|
||||
THROW_BUILTIN_ERROR_RETURN(state, ErrorCode::RangeError, state.context()->staticStrings().TypedArray.string(), false, String::emptyString, ErrorObject::Messages::GlobalObject_InvalidArrayBufferOffset);
|
||||
}
|
||||
|
||||
uint64_t newLength = 0;
|
||||
if (!length.isUndefined()) {
|
||||
newLength = length.toIndex(state);
|
||||
RETURN_IF_PENDING_EXCEPTION
|
||||
if (newLength == Value::InvalidIndexValue) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, state.context()->staticStrings().TypedArray.string(), false, String::emptyString, ErrorObject::Messages::GlobalObject_InvalidArrayBufferOffset);
|
||||
THROW_BUILTIN_ERROR_RETURN(state, ErrorCode::RangeError, state.context()->staticStrings().TypedArray.string(), false, String::emptyString, ErrorObject::Messages::GlobalObject_InvalidArrayBufferOffset);
|
||||
}
|
||||
}
|
||||
|
||||
buffer->throwTypeErrorIfDetached(state);
|
||||
RETURN_IF_PENDING_EXCEPTION
|
||||
size_t bufferByteLength = buffer->byteLength();
|
||||
|
||||
size_t newByteLength = 0;
|
||||
if (length.isUndefined()) {
|
||||
if ((bufferByteLength % elementSize != 0) || (bufferByteLength < offset)) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, state.context()->staticStrings().TypedArray.string(), false, String::emptyString, ErrorObject::Messages::GlobalObject_InvalidArrayBufferOffset);
|
||||
THROW_BUILTIN_ERROR_RETURN(state, ErrorCode::RangeError, state.context()->staticStrings().TypedArray.string(), false, String::emptyString, ErrorObject::Messages::GlobalObject_InvalidArrayBufferOffset);
|
||||
}
|
||||
newByteLength = bufferByteLength - offset;
|
||||
} else {
|
||||
newByteLength = newLength * elementSize;
|
||||
if (offset + newByteLength > bufferByteLength) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, state.context()->staticStrings().TypedArray.string(), false, String::emptyString, ErrorObject::Messages::GlobalObject_InvalidArrayBufferOffset);
|
||||
THROW_BUILTIN_ERROR_RETURN(state, ErrorCode::RangeError, state.context()->staticStrings().TypedArray.string(), false, String::emptyString, ErrorObject::Messages::GlobalObject_InvalidArrayBufferOffset);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -333,12 +363,14 @@ static void initializeTypedArrayFromList(ExecutionState& state, TypedArrayObject
|
|||
uint64_t elementSize = obj->elementSize();
|
||||
uint64_t byteLength = static_cast<uint64_t>(len) * elementSize;
|
||||
ArrayBufferObject* buffer = ArrayBufferObject::allocateArrayBuffer(state, state.context()->globalObject()->arrayBuffer(), byteLength);
|
||||
RETURN_IF_PENDING_EXCEPTION
|
||||
obj->setBuffer(buffer, 0, byteLength, len);
|
||||
|
||||
size_t k = 0;
|
||||
while (k < len) {
|
||||
// Perform ? Set(O, Pk, kValue, true).
|
||||
obj->setIndexedPropertyThrowsException(state, Value(k), values[k]);
|
||||
RETURN_IF_PENDING_EXCEPTION
|
||||
k++;
|
||||
}
|
||||
}
|
||||
|
|
@ -346,17 +378,22 @@ static void initializeTypedArrayFromList(ExecutionState& state, TypedArrayObject
|
|||
static void initializeTypedArrayFromArrayLike(ExecutionState& state, TypedArrayObject* obj, Object* arrayLike)
|
||||
{
|
||||
size_t len = arrayLike->length(state);
|
||||
RETURN_IF_PENDING_EXCEPTION
|
||||
|
||||
// Perform ? AllocateTypedArrayBuffer(O, len).
|
||||
size_t elementSize = obj->elementSize();
|
||||
uint64_t byteLength = static_cast<uint64_t>(len) * elementSize;
|
||||
ArrayBufferObject* buffer = ArrayBufferObject::allocateArrayBuffer(state, state.context()->globalObject()->arrayBuffer(), byteLength);
|
||||
RETURN_IF_PENDING_EXCEPTION
|
||||
obj->setBuffer(buffer, 0, byteLength, len);
|
||||
|
||||
size_t k = 0;
|
||||
while (k < len) {
|
||||
// Perform ? Set(O, Pk, kValue, true).
|
||||
obj->setIndexedPropertyThrowsException(state, Value(k), arrayLike->getIndexedProperty(state, Value(k)).value(state, arrayLike));
|
||||
Value val = arrayLike->getIndexedProperty(state, Value(k)).value(state, arrayLike);
|
||||
RETURN_IF_PENDING_EXCEPTION
|
||||
obj->setIndexedPropertyThrowsException(state, Value(k), val);
|
||||
RETURN_IF_PENDING_EXCEPTION
|
||||
k++;
|
||||
}
|
||||
}
|
||||
|
|
@ -366,7 +403,7 @@ static Value builtinTypedArrayConstructor(ExecutionState& state, Value thisValue
|
|||
{
|
||||
// if NewTarget is undefined, throw a TypeError
|
||||
if (!newTarget.hasValue()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ConstructorRequiresNew);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ConstructorRequiresNew);
|
||||
}
|
||||
|
||||
if (argc == 0) {
|
||||
|
|
@ -377,16 +414,18 @@ static Value builtinTypedArrayConstructor(ExecutionState& state, Value thisValue
|
|||
const Value& firstArg = argv[0];
|
||||
if (!firstArg.isObject()) {
|
||||
uint64_t elemlen = firstArg.toIndex(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (elemlen == Value::InvalidIndexValue) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, state.context()->staticStrings().TypedArray.string(), false, String::emptyString, ErrorObject::Messages::GlobalObject_FirstArgumentInvalidLength);
|
||||
return Value();
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::RangeError, state.context()->staticStrings().TypedArray.string(), false, String::emptyString, ErrorObject::Messages::GlobalObject_FirstArgumentInvalidLength);
|
||||
}
|
||||
return TA::allocateTypedArray(state, newTarget.value(), elemlen);
|
||||
}
|
||||
|
||||
ASSERT(firstArg.isObject());
|
||||
Object* argObj = firstArg.asObject();
|
||||
TypedArrayObject* obj = TA::allocateTypedArray(state, newTarget.value());
|
||||
Value objValue = TA::allocateTypedArray(state, newTarget.value());
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
TypedArrayObject* obj = objValue.asPointerValue()->asTypedArrayObject();
|
||||
|
||||
if (argObj->isTypedArrayObject()) {
|
||||
initializeTypedArrayFromTypedArray(state, obj, argObj->asTypedArrayObject());
|
||||
|
|
@ -396,14 +435,17 @@ static Value builtinTypedArrayConstructor(ExecutionState& state, Value thisValue
|
|||
initializeTypedArrayFromArrayBuffer(state, obj, argObj->asArrayBuffer(), byteOffset, length);
|
||||
} else {
|
||||
Value usingIterator = Object::getMethod(state, argObj, ObjectPropertyName(state.context()->vmInstance()->globalSymbols().iterator));
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (!usingIterator.isUndefined()) {
|
||||
ValueVectorWithInlineStorage values = IteratorObject::iterableToList(state, argObj, usingIterator);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
initializeTypedArrayFromList(state, obj, values);
|
||||
} else {
|
||||
initializeTypedArrayFromArrayLike(state, obj, argObj);
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
|
@ -412,6 +454,7 @@ static Value builtinTypedArrayCopyWithin(ExecutionState& state, Value thisValue,
|
|||
{
|
||||
// validateTypedArray is applied to the this value prior to evaluating the algorithm.
|
||||
TypedArrayObject::validateTypedArray(state, thisValue);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
TypedArrayObject* O = thisValue.asObject()->asTypedArrayObject();
|
||||
|
||||
// Let len be O.[[ArrayLength]].
|
||||
|
|
@ -440,6 +483,7 @@ static Value builtinTypedArrayCopyWithin(ExecutionState& state, Value thisValue,
|
|||
ArrayBuffer* buffer = O->buffer();
|
||||
// If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
|
||||
buffer->throwTypeErrorIfDetached(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Let typedArrayName be the String value of O.[[TypedArrayName]].
|
||||
// Let elementSize be the Number value of the Element Size value specified in Table 59 for typedArrayName.
|
||||
size_t elementSize = O->elementSize();
|
||||
|
|
@ -491,6 +535,7 @@ static Value builtinTypedArrayIndexOf(ExecutionState& state, Value thisValue, si
|
|||
// Let O be the result of calling ToObject passing the this value as the argument.
|
||||
RESOLVE_THIS_BINDING_TO_OBJECT(O, TypedArray, indexOf);
|
||||
TypedArrayObject::validateTypedArray(state, O);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// Let lenValue be this object's [[ArrayLength]] internal slot.
|
||||
// Let len be ToUint32(lenValue).
|
||||
|
|
@ -536,6 +581,7 @@ static Value builtinTypedArrayIndexOf(ExecutionState& state, Value thisValue, si
|
|||
if (kPresent.hasValue()) {
|
||||
// Let elementK be the result of calling the [[Get]] internal method of O with the argument ToString(k).
|
||||
Value elementK = kPresent.value(state, O);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// Let same be the result of applying the Strict Equality Comparison Algorithm to searchElement and elementK.
|
||||
if (elementK.equalsTo(state, argv[0])) {
|
||||
|
|
@ -557,6 +603,7 @@ static Value builtinTypedArrayLastIndexOf(ExecutionState& state, Value thisValue
|
|||
// Let O be the result of calling ToObject passing the this value as the argument.
|
||||
RESOLVE_THIS_BINDING_TO_OBJECT(O, TypedArray, lastIndexOf);
|
||||
TypedArrayObject::validateTypedArray(state, O);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// Let lenValue be this object's [[ArrayLength]] internal slot.
|
||||
// Let len be ToUint32(lenValue).
|
||||
|
|
@ -598,6 +645,7 @@ static Value builtinTypedArrayLastIndexOf(ExecutionState& state, Value thisValue
|
|||
if (kPresent.hasValue()) {
|
||||
// Let elementK be the result of calling the [[Get]] internal method of O with the argument ToString(k).
|
||||
Value elementK = kPresent.value(state, O);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// Let same be the result of applying the Strict Equality Comparison Algorithm to searchElement and elementK.
|
||||
if (elementK.equalsTo(state, argv[0])) {
|
||||
|
|
@ -623,6 +671,7 @@ static Value builtinTypedArrayIncludes(ExecutionState& state, Value thisValue, s
|
|||
// Let O be ? ToObject(this value).
|
||||
RESOLVE_THIS_BINDING_TO_OBJECT(O, TypedArray, includes);
|
||||
TypedArrayObject::validateTypedArray(state, O);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
size_t len = O->asTypedArrayObject()->arrayLength();
|
||||
|
||||
|
|
@ -658,6 +707,7 @@ static Value builtinTypedArrayIncludes(ExecutionState& state, Value thisValue, s
|
|||
while (k < len) {
|
||||
// Let elementK be the result of ? Get(O, ! ToString(k)).
|
||||
Value elementK = O->getIndexedProperty(state, Value(k)).value(state, O);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// If SameValueZero(searchElement, elementK) is true, return true.
|
||||
if (elementK.equalsToByTheSameValueZeroAlgorithm(state, searchElement)) {
|
||||
return Value(true);
|
||||
|
|
@ -675,7 +725,7 @@ static Value builtinTypedArraySet(ExecutionState& state, Value thisValue, size_t
|
|||
{
|
||||
const StaticStrings* strings = &state.context()->staticStrings();
|
||||
if (!thisValue.isObject() || !thisValue.asObject()->isTypedArrayObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->TypedArray.string(), true, strings->set.string(), ErrorObject::Messages::GlobalObject_ThisNotTypedArrayObject);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, strings->TypedArray.string(), true, strings->set.string(), ErrorObject::Messages::GlobalObject_ThisNotTypedArrayObject);
|
||||
}
|
||||
|
||||
TypedArrayObject* target = thisValue.asObject()->asTypedArrayObject();
|
||||
|
|
@ -685,7 +735,7 @@ static Value builtinTypedArraySet(ExecutionState& state, Value thisValue, size_t
|
|||
targetOffset = argv[1].toInteger(state);
|
||||
}
|
||||
if (targetOffset < 0) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, strings->TypedArray.string(), true, strings->set.string(), "Start offset is negative");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::RangeError, strings->TypedArray.string(), true, strings->set.string(), "Start offset is negative");
|
||||
}
|
||||
|
||||
auto typedArrayType = target->typedArrayType();
|
||||
|
|
@ -693,16 +743,19 @@ static Value builtinTypedArraySet(ExecutionState& state, Value thisValue, size_t
|
|||
|
||||
ArrayBuffer* targetBuffer = target->buffer();
|
||||
targetBuffer->throwTypeErrorIfDetached(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
size_t targetLength = target->arrayLength();
|
||||
size_t targetElementSize = target->elementSize();
|
||||
size_t targetByteOffset = target->byteOffset();
|
||||
|
||||
Object* src = argv[0].toObject(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (!src->isTypedArrayObject()) {
|
||||
// 22.2.3.23.1%TypedArray%.prototype.set ( array [ , offset ] )
|
||||
size_t srcLength = src->length(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (srcLength + targetOffset > targetLength) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, strings->TypedArray.string(), true, strings->set.string(), ErrorObject::Messages::GlobalObject_InvalidArrayLength);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::RangeError, strings->TypedArray.string(), true, strings->set.string(), ErrorObject::Messages::GlobalObject_InvalidArrayLength);
|
||||
}
|
||||
|
||||
size_t targetByteIndex = targetOffset * targetElementSize + targetByteOffset;
|
||||
|
|
@ -710,12 +763,15 @@ static Value builtinTypedArraySet(ExecutionState& state, Value thisValue, size_t
|
|||
size_t limit = targetByteIndex + targetElementSize * srcLength;
|
||||
while (targetByteIndex < limit) {
|
||||
Value value = src->get(state, ObjectPropertyName(state, Value(k))).value(state, src);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (UNLIKELY(isBigIntArray)) {
|
||||
value = value.toBigInt(state);
|
||||
} else {
|
||||
value = Value(Value::DoubleToIntConvertibleTestNeeds, value.toNumber(state));
|
||||
}
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
targetBuffer->throwTypeErrorIfDetached(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// Perform SetValueInBuffer(targetBuffer, targetByteIndex, targetType, value, true, "Unordered").
|
||||
targetBuffer->setValueInBuffer(state, targetByteIndex, target->typedArrayType(), value);
|
||||
|
|
@ -732,26 +788,28 @@ static Value builtinTypedArraySet(ExecutionState& state, Value thisValue, size_t
|
|||
TypedArrayObject* srcTypedArray = src->asTypedArrayObject();
|
||||
ArrayBuffer* srcBuffer = srcTypedArray->buffer();
|
||||
srcBuffer->throwTypeErrorIfDetached(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
size_t srcElementSize = srcTypedArray->elementSize();
|
||||
size_t srcLength = srcTypedArray->arrayLength();
|
||||
size_t srcByteOffset = srcTypedArray->byteOffset();
|
||||
|
||||
if (srcLength + targetOffset > targetLength) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, strings->TypedArray.string(), true, strings->set.string(), ErrorObject::Messages::GlobalObject_InvalidArrayLength);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::RangeError, strings->TypedArray.string(), true, strings->set.string(), ErrorObject::Messages::GlobalObject_InvalidArrayLength);
|
||||
}
|
||||
|
||||
// If one of srcType and targetType contains the substring "Big" and the other does not, throw a TypeError exception.
|
||||
auto srcTypedArrayType = srcTypedArray->typedArrayType();
|
||||
bool isSrcBigIntArray = srcTypedArrayType == TypedArrayType::BigInt64 || srcTypedArrayType == TypedArrayType::BigUint64;
|
||||
if (isBigIntArray != isSrcBigIntArray) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->TypedArray.string(), true, strings->set.string(), "Cannot mix BigIntArray with other Array");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, strings->TypedArray.string(), true, strings->set.string(), "Cannot mix BigIntArray with other Array");
|
||||
}
|
||||
|
||||
size_t srcByteIndex = srcByteOffset;
|
||||
if (srcBuffer == targetBuffer) {
|
||||
size_t srcByteLength = srcTypedArray->byteLength();
|
||||
srcBuffer = ArrayBufferObject::cloneArrayBuffer(state, targetBuffer, srcByteOffset, srcByteLength, state.context()->globalObject()->arrayBuffer());
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
srcByteIndex = 0;
|
||||
}
|
||||
|
||||
|
|
@ -787,6 +845,7 @@ static Value builtinTypedArraySome(ExecutionState& state, Value thisValue, size_
|
|||
RESOLVE_THIS_BINDING_TO_OBJECT(O, TypedArray, some);
|
||||
// validateTypedArray is applied to the this value prior to evaluating the algorithm.
|
||||
TypedArrayObject::validateTypedArray(state, O);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// Array.prototype.some as defined in 22.1.3.23 except
|
||||
// that the this object’s [[ArrayLength]] internal slot is accessed
|
||||
|
|
@ -796,8 +855,8 @@ static Value builtinTypedArraySome(ExecutionState& state, Value thisValue, size_
|
|||
// If IsCallable(callbackfn) is false, throw a TypeError exception.
|
||||
Value callbackfn = argv[0];
|
||||
if (!callbackfn.isCallable()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().TypedArray.string(), true,
|
||||
state.context()->staticStrings().some.string(), ErrorObject::Messages::GlobalObject_CallbackNotCallable);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().TypedArray.string(), true,
|
||||
state.context()->staticStrings().some.string(), ErrorObject::Messages::GlobalObject_CallbackNotCallable);
|
||||
}
|
||||
|
||||
Value T;
|
||||
|
|
@ -814,9 +873,11 @@ static Value builtinTypedArraySome(ExecutionState& state, Value thisValue, size_
|
|||
ObjectGetResult kResult = O->getIndexedProperty(state, Value(k));
|
||||
// Let kValue be the result of calling the [[Get]] internal method of O with argument ToString(k).
|
||||
Value kValue = kResult.value(state, O);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Let testResult be the result of calling the [[Call]] internal method of callbackfn with T as the this value and argument list containing kValue, k, and O.
|
||||
Value args[] = { kValue, Value(k), O };
|
||||
Value testResult = Object::call(state, callbackfn, T, 3, args);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// If ToBoolean(testResult) is true, return true.
|
||||
if (testResult.toBoolean(state)) {
|
||||
|
|
@ -836,13 +897,14 @@ static Value builtinTypedArraySort(ExecutionState& state, Value thisValue, size_
|
|||
RESOLVE_THIS_BINDING_TO_OBJECT(O, TypedArray, sort);
|
||||
// Let buffer be TypedArrayObject::validateTypedArray(obj).
|
||||
ArrayBuffer* buffer = TypedArrayObject::validateTypedArray(state, O);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// Let len be the value of O’s [[ArrayLength]] internal slot.
|
||||
int64_t len = O->asTypedArrayObject()->arrayLength();
|
||||
|
||||
Value cmpfn = argv[0];
|
||||
if (!cmpfn.isUndefined() && !cmpfn.isCallable()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().Array.string(), true, state.context()->staticStrings().sort.string(), ErrorObject::Messages::GlobalObject_FirstArgumentNotCallable);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Array.string(), true, state.context()->staticStrings().sort.string(), ErrorObject::Messages::GlobalObject_FirstArgumentNotCallable);
|
||||
}
|
||||
bool defaultSort = (argc == 0) || cmpfn.isUndefined();
|
||||
|
||||
|
|
@ -853,6 +915,8 @@ static Value builtinTypedArraySort(ExecutionState& state, Value thisValue, size_
|
|||
Value args[] = { x, y };
|
||||
double v = Object::call(state, cmpfn, Value(), 2, args).toNumber(state);
|
||||
buffer->throwTypeErrorIfDetached(state);
|
||||
// FIXME THROW
|
||||
ASSERT(!state.hasPendingException());
|
||||
if (std::isnan(v)) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -928,6 +992,7 @@ static Value builtinTypedArrayEvery(ExecutionState& state, Value thisValue, size
|
|||
RESOLVE_THIS_BINDING_TO_OBJECT(O, TypedArray, every);
|
||||
// validateTypedArray is applied to the this value prior to evaluating the algorithm.
|
||||
TypedArrayObject::validateTypedArray(state, O);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// Array.prototype.every as defined in 22.1.3.5 except
|
||||
// that the this object’s [[ArrayLength]] internal slot is accessed
|
||||
|
|
@ -937,8 +1002,8 @@ static Value builtinTypedArrayEvery(ExecutionState& state, Value thisValue, size
|
|||
// If IsCallable(callbackfn) is false, throw a TypeError exception.
|
||||
Value callbackfn = argv[0];
|
||||
if (!callbackfn.isCallable()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().TypedArray.string(), true,
|
||||
state.context()->staticStrings().every.string(), ErrorObject::Messages::GlobalObject_CallbackNotCallable);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().TypedArray.string(), true,
|
||||
state.context()->staticStrings().every.string(), ErrorObject::Messages::GlobalObject_CallbackNotCallable);
|
||||
}
|
||||
|
||||
// If thisArg was supplied, let T be thisArg; else let T be undefined.
|
||||
|
|
@ -953,9 +1018,11 @@ static Value builtinTypedArrayEvery(ExecutionState& state, Value thisValue, size
|
|||
ObjectGetResult value = O->getIndexedProperty(state, Value(k));
|
||||
// Let kValue be the result of calling the [[Get]] internal method of O with argument Pk.
|
||||
Value kValue = value.value(state, O);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Let testResult be the result of calling the [[Call]] internal method of callbackfn with T as the this value and argument list containing kValue, k, and O.
|
||||
Value args[] = { kValue, Value(k), O };
|
||||
Value testResult = Object::call(state, callbackfn, T, 3, args);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
if (!testResult.toBoolean(state)) {
|
||||
return Value(false);
|
||||
|
|
@ -972,6 +1039,7 @@ static Value builtinTypedArrayFill(ExecutionState& state, Value thisValue, size_
|
|||
{
|
||||
// Perform ? TypedArrayObject::validateTypedArray(O).
|
||||
TypedArrayObject::validateTypedArray(state, thisValue);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
TypedArrayObject* O = thisValue.asObject()->asTypedArrayObject();
|
||||
|
||||
// Let len be O.[[ArrayLength]].
|
||||
|
|
@ -986,7 +1054,9 @@ static Value builtinTypedArrayFill(ExecutionState& state, Value thisValue, size_
|
|||
// Otherwise, let value be ? ToNumber(value).
|
||||
// Set value to ? ToNumber(value).
|
||||
value = Value(Value::DoubleToIntConvertibleTestNeeds, argv[0].toNumber(state));
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
}
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Let relativeStart be ? ToInteger(start).
|
||||
double relativeStart = 0;
|
||||
if (argc > 1) {
|
||||
|
|
@ -1004,10 +1074,12 @@ static Value builtinTypedArrayFill(ExecutionState& state, Value thisValue, size_
|
|||
|
||||
// If IsDetachedBuffer(O.[[ViewedArrayBuffer]]) is true, throw a TypeError exception.
|
||||
O->buffer()->throwTypeErrorIfDetached(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// Repeat, while k < final
|
||||
while (k < fin) {
|
||||
O->setIndexedPropertyThrowsException(state, Value(k), value);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
k++;
|
||||
}
|
||||
// return O.
|
||||
|
|
@ -1019,6 +1091,7 @@ static Value builtinTypedArrayFilter(ExecutionState& state, Value thisValue, siz
|
|||
{
|
||||
// Perform ? TypedArrayObject::validateTypedArray(O).
|
||||
TypedArrayObject::validateTypedArray(state, thisValue);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
TypedArrayObject* O = thisValue.asObject()->asTypedArrayObject();
|
||||
|
||||
// Let len be O.[[ArrayLength]].
|
||||
|
|
@ -1027,7 +1100,7 @@ static Value builtinTypedArrayFilter(ExecutionState& state, Value thisValue, siz
|
|||
// If IsCallable(callbackfn) is false, throw a TypeError exception.
|
||||
Value callbackfn = argv[0];
|
||||
if (!callbackfn.isCallable()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().TypedArray.string(), true, state.context()->staticStrings().filter.string(), ErrorObject::Messages::GlobalObject_CallbackNotCallable);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().TypedArray.string(), true, state.context()->staticStrings().filter.string(), ErrorObject::Messages::GlobalObject_CallbackNotCallable);
|
||||
}
|
||||
|
||||
// If thisArg was supplied, let T be thisArg; else let T be undefined.
|
||||
|
|
@ -1045,8 +1118,11 @@ static Value builtinTypedArrayFilter(ExecutionState& state, Value thisValue, siz
|
|||
// Repeat, while k < len
|
||||
while (k < len) {
|
||||
Value kValue = O->getIndexedProperty(state, Value(k)).value(state, O);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
Value args[] = { kValue, Value(k), O };
|
||||
bool selected = Object::call(state, callbackfn, T, 3, args).toBoolean(state);
|
||||
Value val = Object::call(state, callbackfn, T, 3, args);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
bool selected = val.toBoolean(state);
|
||||
if (selected) {
|
||||
kept.push_back(kValue);
|
||||
captured++;
|
||||
|
|
@ -1057,12 +1133,14 @@ static Value builtinTypedArrayFilter(ExecutionState& state, Value thisValue, siz
|
|||
// Let A be ? TypedArraySpeciesCreate(O, « captured »).
|
||||
Value arg[1] = { Value(captured) };
|
||||
Value A = TypedArraySpeciesCreate(state, O, 1, arg);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// Let n be 0.
|
||||
// For each element e of kept
|
||||
for (size_t n = 0; n < kept.size(); n++) {
|
||||
// Let status be Set(A, ToString(n), e, true ).
|
||||
A.asObject()->setIndexedPropertyThrowsException(state, Value(n), kept[n]);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
}
|
||||
// Return A.
|
||||
return A;
|
||||
|
|
@ -1076,6 +1154,7 @@ static Value builtinTypedArrayFind(ExecutionState& state, Value thisValue, size_
|
|||
RESOLVE_THIS_BINDING_TO_OBJECT(O, TypedArray, find);
|
||||
// validateTypedArray is applied to the this value prior to evaluating the algorithm.
|
||||
TypedArrayObject::validateTypedArray(state, O);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// Array.prototype.find as defined in 22.1.3.8 except
|
||||
// that the this object’s [[ArrayLength]] internal slot is accessed
|
||||
|
|
@ -1084,7 +1163,7 @@ static Value builtinTypedArrayFind(ExecutionState& state, Value thisValue, size_
|
|||
|
||||
// If IsCallable(predicate) is false, throw a TypeError exception.
|
||||
if (!predicate.isCallable()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().TypedArray.string(), true, state.context()->staticStrings().find.string(), ErrorObject::Messages::GlobalObject_CallbackNotCallable);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().TypedArray.string(), true, state.context()->staticStrings().find.string(), ErrorObject::Messages::GlobalObject_CallbackNotCallable);
|
||||
}
|
||||
|
||||
// Let k be 0.
|
||||
|
|
@ -1093,9 +1172,12 @@ static Value builtinTypedArrayFind(ExecutionState& state, Value thisValue, size_
|
|||
while (k < len) {
|
||||
// Let kValue be Get(O, Pk).
|
||||
Value kValue = O->getIndexedProperty(state, Value(k)).value(state, O);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Let testResult be ToBoolean(Call(predicate, thisArg, «kValue, k, O»)).
|
||||
Value args[] = { kValue, Value(k), O };
|
||||
bool testResult = Object::call(state, predicate, thisArg, 3, args).toBoolean(state);
|
||||
Value res = Object::call(state, predicate, thisArg, 3, args);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
bool testResult = res.toBoolean(state);
|
||||
// If testResult is true, return kValue.
|
||||
if (testResult) {
|
||||
return kValue;
|
||||
|
|
@ -1115,6 +1197,7 @@ static Value builtinTypedArrayFindIndex(ExecutionState& state, Value thisValue,
|
|||
RESOLVE_THIS_BINDING_TO_OBJECT(O, TypedArray, findIndex);
|
||||
// validateTypedArray is applied to the this value prior to evaluating the algorithm.
|
||||
TypedArrayObject::validateTypedArray(state, O);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// Array.prototype.findIndex as defined in 22.1.3.9 except
|
||||
// that the this object’s [[ArrayLength]] internal slot is accessed
|
||||
|
|
@ -1123,7 +1206,7 @@ static Value builtinTypedArrayFindIndex(ExecutionState& state, Value thisValue,
|
|||
|
||||
// If IsCallable(predicate) is false, throw a TypeError exception.
|
||||
if (!predicate.isCallable()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().TypedArray.string(), true, state.context()->staticStrings().findIndex.string(), ErrorObject::Messages::GlobalObject_CallbackNotCallable);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().TypedArray.string(), true, state.context()->staticStrings().findIndex.string(), ErrorObject::Messages::GlobalObject_CallbackNotCallable);
|
||||
}
|
||||
|
||||
// Let k be 0.
|
||||
|
|
@ -1132,9 +1215,12 @@ static Value builtinTypedArrayFindIndex(ExecutionState& state, Value thisValue,
|
|||
while (k < len) {
|
||||
// Let kValue be ? Get(O, Pk).
|
||||
Value kValue = O->getIndexedProperty(state, Value(k)).value(state, O);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Let testResult be ToBoolean(? Call(predicate, thisArg, « kValue, k, O »)).
|
||||
Value args[] = { kValue, Value(k), O };
|
||||
bool testResult = Object::call(state, predicate, thisArg, 3, args).toBoolean(state);
|
||||
Value res = Object::call(state, predicate, thisArg, 3, args);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
bool testResult = res.toBoolean(state);
|
||||
// If testResult is true, return k.
|
||||
if (testResult) {
|
||||
return Value(k);
|
||||
|
|
@ -1154,13 +1240,14 @@ static Value builtinTypedArrayFindLast(ExecutionState& state, Value thisValue, s
|
|||
RESOLVE_THIS_BINDING_TO_OBJECT(O, TypedArray, find);
|
||||
// validateTypedArray is applied to the this value prior to evaluating the algorithm.
|
||||
TypedArrayObject::validateTypedArray(state, O);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// Let len be O.[[ArrayLength]].
|
||||
int64_t len = static_cast<int64_t>(O->asTypedArrayObject()->arrayLength());
|
||||
|
||||
// If IsCallable(predicate) is false, throw a TypeError exception.
|
||||
if (!predicate.isCallable()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().TypedArray.string(), true, state.context()->staticStrings().findLast.string(), ErrorObject::Messages::GlobalObject_CallbackNotCallable);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().TypedArray.string(), true, state.context()->staticStrings().findLast.string(), ErrorObject::Messages::GlobalObject_CallbackNotCallable);
|
||||
}
|
||||
|
||||
// Let k be len - 1.
|
||||
|
|
@ -1170,9 +1257,12 @@ static Value builtinTypedArrayFindLast(ExecutionState& state, Value thisValue, s
|
|||
while (k >= 0) {
|
||||
// Let kValue be Get(O, Pk).
|
||||
kValue = O->getIndexedProperty(state, Value(k)).value(state, O);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Let testResult be ToBoolean(Call(predicate, thisArg, «kValue, k, O»)).
|
||||
Value args[] = { kValue, Value(k), O };
|
||||
bool testResult = Object::call(state, predicate, thisArg, 3, args).toBoolean(state);
|
||||
Value res = Object::call(state, predicate, thisArg, 3, args);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
bool testResult = res.toBoolean(state);
|
||||
// If testResult is true, return kValue.
|
||||
if (testResult) {
|
||||
return kValue;
|
||||
|
|
@ -1192,13 +1282,14 @@ static Value builtinTypedArrayFindLastIndex(ExecutionState& state, Value thisVal
|
|||
RESOLVE_THIS_BINDING_TO_OBJECT(O, TypedArray, findIndex);
|
||||
// validateTypedArray is applied to the this value prior to evaluating the algorithm.
|
||||
TypedArrayObject::validateTypedArray(state, O);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// Let len be O.[[ArrayLength]].
|
||||
int64_t len = static_cast<int64_t>(O->asTypedArrayObject()->arrayLength());
|
||||
|
||||
// If IsCallable(predicate) is false, throw a TypeError exception.
|
||||
if (!predicate.isCallable()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().TypedArray.string(), true, state.context()->staticStrings().findIndex.string(), ErrorObject::Messages::GlobalObject_CallbackNotCallable);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().TypedArray.string(), true, state.context()->staticStrings().findIndex.string(), ErrorObject::Messages::GlobalObject_CallbackNotCallable);
|
||||
}
|
||||
|
||||
// Let k be len - 1.
|
||||
|
|
@ -1208,9 +1299,12 @@ static Value builtinTypedArrayFindLastIndex(ExecutionState& state, Value thisVal
|
|||
while (k >= 0) {
|
||||
// Let kValue be ? Get(O, Pk).
|
||||
Value kValue = O->getIndexedProperty(state, Value(k)).value(state, O);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Let testResult be ToBoolean(? Call(predicate, thisArg, « kValue, k, O »)).
|
||||
Value args[] = { kValue, Value(k), O };
|
||||
bool testResult = Object::call(state, predicate, thisArg, 3, args).toBoolean(state);
|
||||
Value res = Object::call(state, predicate, thisArg, 3, args);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
bool testResult = res.toBoolean(state);
|
||||
// If testResult is true, return k.
|
||||
if (testResult) {
|
||||
return Value(k);
|
||||
|
|
@ -1228,6 +1322,7 @@ static Value builtinTypedArrayForEach(ExecutionState& state, Value thisValue, si
|
|||
RESOLVE_THIS_BINDING_TO_OBJECT(O, TypedArray, forEach);
|
||||
// validateTypedArray is applied to the this value prior to evaluating the algorithm.
|
||||
TypedArrayObject::validateTypedArray(state, O);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// Array.prototype.forEach as defined in 22.1.3.10 except
|
||||
// that the this object’s [[ArrayLength]] internal slot is accessed
|
||||
|
|
@ -1236,8 +1331,8 @@ static Value builtinTypedArrayForEach(ExecutionState& state, Value thisValue, si
|
|||
|
||||
Value callbackfn = argv[0];
|
||||
if (!callbackfn.isCallable()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().TypedArray.string(), true,
|
||||
state.context()->staticStrings().forEach.string(), ErrorObject::Messages::GlobalObject_CallbackNotCallable);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().TypedArray.string(), true,
|
||||
state.context()->staticStrings().forEach.string(), ErrorObject::Messages::GlobalObject_CallbackNotCallable);
|
||||
}
|
||||
|
||||
// If thisArg was supplied, let T be thisArg; else let T be undefined.
|
||||
|
|
@ -1251,8 +1346,10 @@ static Value builtinTypedArrayForEach(ExecutionState& state, Value thisValue, si
|
|||
while (k < len) {
|
||||
ObjectGetResult res = O->getIndexedProperty(state, Value(k));
|
||||
Value kValue = res.value(state, O);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
Value args[] = { kValue, Value(k), O };
|
||||
Object::call(state, callbackfn, T, 3, args);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
k++;
|
||||
}
|
||||
// Return undefined.
|
||||
|
|
@ -1265,6 +1362,7 @@ static Value builtinTypedArrayJoin(ExecutionState& state, Value thisValue, size_
|
|||
RESOLVE_THIS_BINDING_TO_OBJECT(O, TypedArray, join);
|
||||
// validateTypedArray is applied to the this value prior to evaluating the algorithm.
|
||||
TypedArrayObject::validateTypedArray(state, O);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// Array.prototype.join as defined in 22.1.3.12 except
|
||||
// that the this object’s [[ArrayLength]] internal slot is accessed
|
||||
|
|
@ -1279,6 +1377,7 @@ static Value builtinTypedArrayJoin(ExecutionState& state, Value thisValue, size_
|
|||
sep = state.context()->staticStrings().asciiTable[(size_t)','].string();
|
||||
} else {
|
||||
sep = separator.toString(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
}
|
||||
|
||||
if (!state.context()->toStringRecursionPreventer()->canInvokeToString(O) || len == 0) {
|
||||
|
|
@ -1288,24 +1387,28 @@ static Value builtinTypedArrayJoin(ExecutionState& state, Value thisValue, size_
|
|||
|
||||
StringBuilder builder;
|
||||
Value elem = O->getIndexedProperty(state, Value(0)).value(state, O);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (elem.isUndefinedOrNull()) {
|
||||
elem = String::emptyString;
|
||||
}
|
||||
builder.appendString(elem.toString(state));
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
size_t curIndex = 1;
|
||||
while (curIndex < len) {
|
||||
if (sep->length() > 0) {
|
||||
if (static_cast<double>(builder.contentLength()) > static_cast<double>(lenMax - sep->length())) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, ErrorObject::Messages::String_InvalidStringLength);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::RangeError, ErrorObject::Messages::String_InvalidStringLength);
|
||||
}
|
||||
builder.appendString(sep);
|
||||
}
|
||||
elem = O->getIndexedProperty(state, Value(curIndex)).value(state, O);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (elem.isUndefinedOrNull()) {
|
||||
elem = String::emptyString;
|
||||
}
|
||||
builder.appendString(elem.toString(state));
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
curIndex++;
|
||||
}
|
||||
|
||||
|
|
@ -1317,6 +1420,7 @@ static Value builtinTypedArrayMap(ExecutionState& state, Value thisValue, size_t
|
|||
{
|
||||
// Perform ? TypedArrayObject::validateTypedArray(O).
|
||||
TypedArrayObject::validateTypedArray(state, thisValue);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
TypedArrayObject* O = thisValue.asObject()->asTypedArrayObject();
|
||||
|
||||
// Let len be O.[[ArrayLength]].
|
||||
|
|
@ -1325,7 +1429,7 @@ static Value builtinTypedArrayMap(ExecutionState& state, Value thisValue, size_t
|
|||
// If IsCallable(callbackfn) is false, throw a TypeError exception.
|
||||
Value callbackfn = argv[0];
|
||||
if (!callbackfn.isCallable()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().TypedArray.string(), true, state.context()->staticStrings().map.string(), ErrorObject::Messages::GlobalObject_CallbackNotCallable);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().TypedArray.string(), true, state.context()->staticStrings().map.string(), ErrorObject::Messages::GlobalObject_CallbackNotCallable);
|
||||
}
|
||||
|
||||
// If thisArg was supplied, let T be thisArg; else let T be undefined.
|
||||
|
|
@ -1337,15 +1441,19 @@ static Value builtinTypedArrayMap(ExecutionState& state, Value thisValue, size_t
|
|||
// Let A be ? TypedArraySpeciesCreate(O, « len »).
|
||||
Value arg[1] = { Value(len) };
|
||||
Value A = TypedArraySpeciesCreate(state, O, 1, arg);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// Let k be 0.
|
||||
size_t k = 0;
|
||||
// Repeat, while k < len
|
||||
while (k < len) {
|
||||
Value kValue = O->getIndexedProperty(state, Value(k)).value(state, O);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
Value args[] = { kValue, Value(k), O };
|
||||
Value mappedValue = Object::call(state, callbackfn, T, 3, args);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
A.asObject()->setIndexedPropertyThrowsException(state, Value(k), mappedValue);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
k++;
|
||||
}
|
||||
// Return A.
|
||||
|
|
@ -1358,6 +1466,7 @@ static Value builtinTypedArrayReduce(ExecutionState& state, Value thisValue, siz
|
|||
RESOLVE_THIS_BINDING_TO_OBJECT(O, TypedArray, reduce);
|
||||
// validateTypedArray is applied to the this value prior to evaluating the algorithm.
|
||||
TypedArrayObject::validateTypedArray(state, O);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// Array.prototype.reduce as defined in 22.1.3.18 except
|
||||
// that the this object’s [[ArrayLength]] internal slot is accessed
|
||||
|
|
@ -1366,11 +1475,11 @@ static Value builtinTypedArrayReduce(ExecutionState& state, Value thisValue, siz
|
|||
|
||||
Value callbackfn = argv[0];
|
||||
if (!callbackfn.isCallable()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().TypedArray.string(), true, state.context()->staticStrings().reduce.string(), ErrorObject::Messages::GlobalObject_CallbackNotCallable);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().TypedArray.string(), true, state.context()->staticStrings().reduce.string(), ErrorObject::Messages::GlobalObject_CallbackNotCallable);
|
||||
}
|
||||
|
||||
if (len == 0 && argc < 2) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().TypedArray.string(), true, state.context()->staticStrings().reduce.string(), ErrorObject::Messages::GlobalObject_ReduceError);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().TypedArray.string(), true, state.context()->staticStrings().reduce.string(), ErrorObject::Messages::GlobalObject_ReduceError);
|
||||
}
|
||||
|
||||
size_t k = 0; // 6
|
||||
|
|
@ -1380,13 +1489,16 @@ static Value builtinTypedArrayReduce(ExecutionState& state, Value thisValue, siz
|
|||
} else { // 8
|
||||
ObjectGetResult res = O->getIndexedProperty(state, Value(k));
|
||||
accumulator = res.value(state, O);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
k++;
|
||||
}
|
||||
while (k < len) { // 9
|
||||
ObjectGetResult res = O->getIndexedProperty(state, Value(k));
|
||||
Value kValue = res.value(state, O);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
Value args[] = { accumulator, kValue, Value(k), O };
|
||||
accumulator = Object::call(state, callbackfn, Value(), 4, args);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
k++;
|
||||
}
|
||||
return accumulator;
|
||||
|
|
@ -1398,6 +1510,7 @@ static Value builtinTypedArrayReduceRight(ExecutionState& state, Value thisValue
|
|||
RESOLVE_THIS_BINDING_TO_OBJECT(O, TypedArray, reduceRight);
|
||||
// validateTypedArray is applied to the this value prior to evaluating the algorithm.
|
||||
TypedArrayObject::validateTypedArray(state, O);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// Array.prototype.reduceRight as defined in 22.1.3.19 except
|
||||
// that the this object’s [[ArrayLength]] internal slot is accessed
|
||||
|
|
@ -1407,13 +1520,13 @@ static Value builtinTypedArrayReduceRight(ExecutionState& state, Value thisValue
|
|||
// If IsCallable(callbackfn) is false, throw a TypeError exception.
|
||||
Value callbackfn = argv[0];
|
||||
if (!callbackfn.isCallable()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().TypedArray.string(), true,
|
||||
state.context()->staticStrings().reduceRight.string(), ErrorObject::Messages::GlobalObject_CallbackNotCallable);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().TypedArray.string(), true,
|
||||
state.context()->staticStrings().reduceRight.string(), ErrorObject::Messages::GlobalObject_CallbackNotCallable);
|
||||
}
|
||||
|
||||
// If len is 0 and initialValue is not present, throw a TypeError exception.
|
||||
if (len == 0 && argc < 2) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().TypedArray.string(), true, state.context()->staticStrings().reduceRight.string(), ErrorObject::Messages::GlobalObject_ReduceError);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().TypedArray.string(), true, state.context()->staticStrings().reduceRight.string(), ErrorObject::Messages::GlobalObject_ReduceError);
|
||||
}
|
||||
|
||||
// Let k be len-1.
|
||||
|
|
@ -1428,6 +1541,7 @@ static Value builtinTypedArrayReduceRight(ExecutionState& state, Value thisValue
|
|||
// Else, initialValue is not present
|
||||
ObjectGetResult res = O->getIndexedProperty(state, Value(k));
|
||||
accumulator = res.value(state, O);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
k--;
|
||||
}
|
||||
|
||||
|
|
@ -1435,8 +1549,10 @@ static Value builtinTypedArrayReduceRight(ExecutionState& state, Value thisValue
|
|||
while (k >= 0) {
|
||||
ObjectGetResult res = O->getIndexedProperty(state, Value(k));
|
||||
Value kValue = res.value(state, O);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
Value args[] = { accumulator, kValue, Value(k), O };
|
||||
accumulator = Object::call(state, callbackfn, Value(), 4, args);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
k--;
|
||||
}
|
||||
// Return accumulator.
|
||||
|
|
@ -1449,6 +1565,7 @@ static Value builtinTypedArrayReverse(ExecutionState& state, Value thisValue, si
|
|||
RESOLVE_THIS_BINDING_TO_OBJECT(O, TypedArray, reverse);
|
||||
// validateTypedArray is applied to the this value prior to evaluating the algorithm.
|
||||
TypedArrayObject::validateTypedArray(state, O);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// Array.prototype.reverse as defined in 22.1.3.20 except
|
||||
// that the this object’s [[ArrayLength]] internal slot is accessed
|
||||
|
|
@ -1464,13 +1581,15 @@ static Value builtinTypedArrayReverse(ExecutionState& state, Value thisValue, si
|
|||
RELEASE_ASSERT(upperResult.hasValue() && lowerResult.hasValue());
|
||||
|
||||
Value upperValue = upperResult.value(state, O);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
Value lowerValue = lowerResult.value(state, O);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
if (!O->setIndexedProperty(state, Value(lower), upperValue)) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().TypedArray.string(), false, String::emptyString, ErrorObject::Messages::DefineProperty_NotWritable);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().TypedArray.string(), false, String::emptyString, ErrorObject::Messages::DefineProperty_NotWritable);
|
||||
}
|
||||
if (!O->setIndexedProperty(state, Value(upper), lowerValue)) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().TypedArray.string(), false, String::emptyString, ErrorObject::Messages::DefineProperty_NotWritable);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().TypedArray.string(), false, String::emptyString, ErrorObject::Messages::DefineProperty_NotWritable);
|
||||
}
|
||||
|
||||
lower++;
|
||||
|
|
@ -1484,6 +1603,7 @@ static Value builtinTypedArraySlice(ExecutionState& state, Value thisValue, size
|
|||
// Let O be the this value.
|
||||
// Perform ? TypedArrayObject::validateTypedArray(O).
|
||||
TypedArrayObject::validateTypedArray(state, thisValue);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
TypedArrayObject* O = thisValue.asObject()->asTypedArrayObject();
|
||||
|
||||
// Let len be the value of O’s [[ArrayLength]] internal slot.
|
||||
|
|
@ -1501,6 +1621,7 @@ static Value builtinTypedArraySlice(ExecutionState& state, Value thisValue, size
|
|||
|
||||
Value arg[1] = { Value(count) };
|
||||
Value A = TypedArraySpeciesCreate(state, O, 1, arg);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
TypedArrayObject* target = A.asObject()->asTypedArrayObject();
|
||||
|
||||
// If SameValue(srcType, targetType) is false, then
|
||||
|
|
@ -1508,8 +1629,11 @@ static Value builtinTypedArraySlice(ExecutionState& state, Value thisValue, size
|
|||
size_t n = 0;
|
||||
while (k < finalEnd) {
|
||||
O->buffer()->throwTypeErrorIfDetached(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
Value kValue = O->getIndexedProperty(state, Value(k)).value(state, O);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
A.asObject()->setIndexedPropertyThrowsException(state, Value(n), kValue);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
k++;
|
||||
n++;
|
||||
}
|
||||
|
|
@ -1517,6 +1641,7 @@ static Value builtinTypedArraySlice(ExecutionState& state, Value thisValue, size
|
|||
// Else if count > 0,
|
||||
ArrayBuffer* srcBuffer = O->buffer();
|
||||
srcBuffer->throwTypeErrorIfDetached(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
ArrayBuffer* targetBuffer = target->buffer();
|
||||
|
||||
size_t elementSize = O->elementSize();
|
||||
|
|
@ -1544,6 +1669,7 @@ static Value builtinTypedArrayToLocaleString(ExecutionState& state, Value thisVa
|
|||
RESOLVE_THIS_BINDING_TO_OBJECT(array, TypedArray, toLocaleString);
|
||||
// validateTypedArray is applied to the this value prior to evaluating the algorithm.
|
||||
TypedArrayObject::validateTypedArray(state, array);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// Array.prototype.toLocaleString as defined in 22.1.3.26 except
|
||||
// that the this object’s [[ArrayLength]] internal slot is accessed
|
||||
|
|
@ -1576,11 +1702,15 @@ static Value builtinTypedArrayToLocaleString(ExecutionState& state, Value thisVa
|
|||
}
|
||||
// Let nextElement be ? Get(array, ! ToString(k)).
|
||||
Value nextElement = array->getIndexedProperty(state, Value(k)).value(state, array);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// If nextElement is not undefined or null, then
|
||||
ASSERT(!nextElement.isUndefinedOrNull());
|
||||
// Let S be ? ToString(? Invoke(nextElement, "toLocaleString")).
|
||||
Value func = nextElement.toObject(state)->get(state, state.context()->staticStrings().toLocaleString).value(state, nextElement);
|
||||
String* S = Object::call(state, func, nextElement, 0, nullptr).toString(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
Value res = Object::call(state, func, nextElement, 0, nullptr);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
String* S = res.toString(state);
|
||||
// Set R to the string-concatenation of R and S.
|
||||
StringBuilder builder2;
|
||||
builder2.appendString(R);
|
||||
|
|
@ -1599,6 +1729,7 @@ static Value builtinTypedArrayKeys(ExecutionState& state, Value thisValue, size_
|
|||
{
|
||||
// Perform ? TypedArrayObject::validateTypedArray(O).
|
||||
TypedArrayObject::validateTypedArray(state, thisValue);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Return CreateArrayIterator(O, "key").
|
||||
return thisValue.asObject()->keys(state);
|
||||
}
|
||||
|
|
@ -1607,6 +1738,7 @@ static Value builtinTypedArrayValues(ExecutionState& state, Value thisValue, siz
|
|||
{
|
||||
// Perform ? TypedArrayObject::validateTypedArray(O).
|
||||
TypedArrayObject::validateTypedArray(state, thisValue);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
return thisValue.asObject()->values(state);
|
||||
}
|
||||
|
||||
|
|
@ -1614,6 +1746,7 @@ static Value builtinTypedArrayValues(ExecutionState& state, Value thisValue, siz
|
|||
static Value builtinTypedArrayEntries(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
TypedArrayObject::validateTypedArray(state, thisValue);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
return thisValue.asObject()->entries(state);
|
||||
}
|
||||
|
||||
|
|
@ -1634,8 +1767,10 @@ static Value builtinTypedArrayToStringTagGetter(ExecutionState& state, Value thi
|
|||
static Value builtinTypedArrayAt(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
TypedArrayObject::validateTypedArray(state, thisValue);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
Object* obj = thisValue.asObject();
|
||||
size_t len = obj->length(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
double relativeStart = argv[0].toInteger(state);
|
||||
if (relativeStart < 0) {
|
||||
relativeStart = len + relativeStart;
|
||||
|
|
|
|||
|
|
@ -30,13 +30,13 @@ namespace Escargot {
|
|||
static Value builtinWeakMapConstructor(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (!newTarget.hasValue()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ConstructorRequiresNew);
|
||||
return Value();
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ConstructorRequiresNew);
|
||||
}
|
||||
|
||||
Object* proto = Object::getPrototypeFromConstructor(state, newTarget.value(), [](ExecutionState& state, Context* constructorRealm) -> Object* {
|
||||
return constructorRealm->globalObject()->weakMapPrototype();
|
||||
});
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
WeakMapObject* weakMap = new WeakMapObject(state, proto);
|
||||
|
||||
|
|
@ -46,40 +46,54 @@ static Value builtinWeakMapConstructor(ExecutionState& state, Value thisValue, s
|
|||
|
||||
Value iterable = argv[0];
|
||||
Value add = weakMap->Object::get(state, ObjectPropertyName(state.context()->staticStrings().set)).value(state, weakMap);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (!add.isCallable()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::NOT_Callable);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::NOT_Callable);
|
||||
}
|
||||
|
||||
auto iteratorRecord = IteratorObject::getIterator(state, iterable);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
while (true) {
|
||||
auto next = IteratorObject::iteratorStep(state, iteratorRecord);
|
||||
if (!next.hasValue()) {
|
||||
return weakMap;
|
||||
}
|
||||
{
|
||||
auto next = IteratorObject::iteratorStep(state, iteratorRecord);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (!next.hasValue()) {
|
||||
return weakMap;
|
||||
}
|
||||
|
||||
Value nextItem = IteratorObject::iteratorValue(state, next.value());
|
||||
if (!nextItem.isObject()) {
|
||||
ErrorObject* error = ErrorObject::createError(state, ErrorCode::TypeError, new ASCIIString("TypeError"));
|
||||
return IteratorObject::iteratorClose(state, iteratorRecord, error, true);
|
||||
}
|
||||
Value nextItem = IteratorObject::iteratorValue(state, next.value());
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (!nextItem.isObject()) {
|
||||
ErrorObject* error = ErrorObject::createError(state, ErrorCode::TypeError, new ASCIIString("TypeError"));
|
||||
return IteratorObject::iteratorClose(state, iteratorRecord, error, true);
|
||||
}
|
||||
|
||||
try {
|
||||
Value k = nextItem.asObject()->getIndexedProperty(state, Value(0)).value(state, nextItem);
|
||||
if (UNLIKELY(state.hasPendingException()))
|
||||
goto IfAbrupt;
|
||||
Value v = nextItem.asObject()->getIndexedProperty(state, Value(1)).value(state, nextItem);
|
||||
if (UNLIKELY(state.hasPendingException()))
|
||||
goto IfAbrupt;
|
||||
Value argv[2] = { k, v };
|
||||
Object::call(state, add, weakMap, 2, argv);
|
||||
} catch (const Value& v) {
|
||||
Value exception = v;
|
||||
return IteratorObject::iteratorClose(state, iteratorRecord, exception, true);
|
||||
if (UNLIKELY(state.hasPendingException()))
|
||||
goto IfAbrupt;
|
||||
continue;
|
||||
}
|
||||
|
||||
IfAbrupt : {
|
||||
ASSERT(state.hasPendingException());
|
||||
Value exception = state.detachPendingException();
|
||||
return IteratorObject::iteratorClose(state, iteratorRecord, exception, true);
|
||||
}
|
||||
}
|
||||
return weakMap;
|
||||
}
|
||||
|
||||
#define RESOLVE_THIS_BINDING_TO_WEAKMAP(NAME, OBJ, BUILT_IN_METHOD) \
|
||||
if (!thisValue.isObject() || !thisValue.asObject()->isWeakMapObject()) { \
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().OBJ.string(), true, state.context()->staticStrings().BUILT_IN_METHOD.string(), ErrorObject::Messages::GlobalObject_CalledOnIncompatibleReceiver); \
|
||||
} \
|
||||
#define RESOLVE_THIS_BINDING_TO_WEAKMAP(NAME, OBJ, BUILT_IN_METHOD) \
|
||||
if (!thisValue.isObject() || !thisValue.asObject()->isWeakMapObject()) { \
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().OBJ.string(), true, state.context()->staticStrings().BUILT_IN_METHOD.string(), ErrorObject::Messages::GlobalObject_CalledOnIncompatibleReceiver); \
|
||||
} \
|
||||
WeakMapObject* NAME = thisValue.asObject()->asWeakMapObject();
|
||||
|
||||
static Value builtinWeakMapDelete(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
|
|
@ -116,7 +130,7 @@ static Value builtinWeakMapSet(ExecutionState& state, Value thisValue, size_t ar
|
|||
{
|
||||
RESOLVE_THIS_BINDING_TO_WEAKMAP(M, WeakMap, set);
|
||||
if (!argv[0].isObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Invalid value used as weak map key");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Invalid value used as weak map key");
|
||||
}
|
||||
|
||||
M->set(state, argv[0].asObject(), argv[1]);
|
||||
|
|
|
|||
|
|
@ -29,17 +29,17 @@ namespace Escargot {
|
|||
static Value builtinWeakRefConstructor(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (!newTarget.hasValue()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ConstructorRequiresNew);
|
||||
return Value();
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ConstructorRequiresNew);
|
||||
}
|
||||
if (argc == 0 || !argv[0].isObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "target is not object");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "target is not object");
|
||||
}
|
||||
|
||||
// Let weakRef be ? OrdinaryCreateFromConstructor(NewTarget, "%WeakRefPrototype%", « [[WeakRefTarget]] »).
|
||||
Object* proto = Object::getPrototypeFromConstructor(state, newTarget.value(), [](ExecutionState& state, Context* constructorRealm) -> Object* {
|
||||
return constructorRealm->globalObject()->weakRefPrototype();
|
||||
});
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
WeakRefObject* weakRef = new WeakRefObject(state, proto, argv[0].asObject());
|
||||
|
||||
return weakRef;
|
||||
|
|
@ -49,7 +49,7 @@ static Value builtinWeakRefConstructor(ExecutionState& state, Value thisValue, s
|
|||
static Value builtinWeakRefDeRef(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (!thisValue.isObject() || !thisValue.asObject()->isWeakRefObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_CalledOnIncompatibleReceiver);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_CalledOnIncompatibleReceiver);
|
||||
}
|
||||
// Let weakRef be the this value.
|
||||
WeakRefObject* weakRef = thisValue.asObject()->asWeakRefObject();
|
||||
|
|
|
|||
|
|
@ -31,13 +31,13 @@ namespace Escargot {
|
|||
static Value builtinWeakSetConstructor(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (!newTarget.hasValue()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ConstructorRequiresNew);
|
||||
return Value();
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ConstructorRequiresNew);
|
||||
}
|
||||
|
||||
Object* proto = Object::getPrototypeFromConstructor(state, newTarget.value(), [](ExecutionState& state, Context* constructorRealm) -> Object* {
|
||||
return constructorRealm->globalObject()->weakSetPrototype();
|
||||
});
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
WeakSetObject* weakSet = new WeakSetObject(state, proto);
|
||||
|
||||
|
|
@ -49,25 +49,28 @@ static Value builtinWeakSetConstructor(ExecutionState& state, Value thisValue, s
|
|||
return weakSet;
|
||||
}
|
||||
Value add = weakSet->get(state, ObjectPropertyName(state.context()->staticStrings().add)).value(state, weakSet);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (!add.isCallable()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::NOT_Callable);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::NOT_Callable);
|
||||
}
|
||||
|
||||
auto iteratorRecord = IteratorObject::getIterator(state, iterable);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
while (true) {
|
||||
auto next = IteratorObject::iteratorStep(state, iteratorRecord);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (!next.hasValue()) {
|
||||
return weakSet;
|
||||
}
|
||||
|
||||
Value nextValue = IteratorObject::iteratorValue(state, next.value());
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
try {
|
||||
Value argv[1] = { nextValue };
|
||||
Object::call(state, add, weakSet, 1, argv);
|
||||
} catch (const Value& v) {
|
||||
Value exceptionValue = v;
|
||||
Value argv[1] = { nextValue };
|
||||
Object::call(state, add, weakSet, 1, argv);
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
Value exceptionValue = state.detachPendingException();
|
||||
return IteratorObject::iteratorClose(state, iteratorRecord, exceptionValue, true);
|
||||
}
|
||||
}
|
||||
|
|
@ -75,17 +78,17 @@ static Value builtinWeakSetConstructor(ExecutionState& state, Value thisValue, s
|
|||
return weakSet;
|
||||
}
|
||||
|
||||
#define RESOLVE_THIS_BINDING_TO_WEAKSET(NAME, OBJ, BUILT_IN_METHOD) \
|
||||
if (!thisValue.isObject() || !thisValue.asObject()->isWeakSetObject()) { \
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().OBJ.string(), true, state.context()->staticStrings().BUILT_IN_METHOD.string(), ErrorObject::Messages::GlobalObject_CalledOnIncompatibleReceiver); \
|
||||
} \
|
||||
#define RESOLVE_THIS_BINDING_TO_WEAKSET(NAME, OBJ, BUILT_IN_METHOD) \
|
||||
if (!thisValue.isObject() || !thisValue.asObject()->isWeakSetObject()) { \
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().OBJ.string(), true, state.context()->staticStrings().BUILT_IN_METHOD.string(), ErrorObject::Messages::GlobalObject_CalledOnIncompatibleReceiver); \
|
||||
} \
|
||||
WeakSetObject* NAME = thisValue.asObject()->asWeakSetObject();
|
||||
|
||||
static Value builtinWeakSetAdd(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
RESOLVE_THIS_BINDING_TO_WEAKSET(S, WeakSet, add);
|
||||
if (!argv[0].isObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Invalid value used as weak set key");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Invalid value used as weak set key");
|
||||
}
|
||||
|
||||
S->add(state, argv[0].asObject());
|
||||
|
|
|
|||
|
|
@ -340,11 +340,7 @@ void ByteCodeGenerator::collectByteCodeLOCData(Context* context, InterpretedCode
|
|||
ctx.m_breakpointContext = &breakpointContext;
|
||||
#endif /* ESCARGOT_DEBUGGER */
|
||||
|
||||
try {
|
||||
ast->generateStatementByteCode(&block, &ctx);
|
||||
} catch (...) {
|
||||
// ignore error
|
||||
}
|
||||
ast->generateStatementByteCode(&block, &ctx);
|
||||
|
||||
// reset ASTAllocator
|
||||
context->astAllocator().reset();
|
||||
|
|
|
|||
|
|
@ -216,15 +216,13 @@ struct ByteCodeGenerateContext {
|
|||
|
||||
size_t getRegister()
|
||||
{
|
||||
if (UNLIKELY(m_baseRegisterCount >= REGULAR_REGISTER_LIMIT)) {
|
||||
throw "register limit exceed while generate byte code";
|
||||
}
|
||||
ASSERT(m_baseRegisterCount < REGULAR_REGISTER_LIMIT);
|
||||
#ifdef STACK_GROWS_DOWN
|
||||
if (UNLIKELY(m_stackLimit > (size_t)currentStackPointer())) {
|
||||
#else
|
||||
if (UNLIKELY(m_stackLimit < (size_t)currentStackPointer())) {
|
||||
#endif
|
||||
throw "native stack limit exceed while generate byte code";
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
m_registerStack->push_back(m_baseRegisterCount);
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -337,7 +337,7 @@ static void testDeclareGlobalFunctions(ExecutionState& state, InterpretedCodeBlo
|
|||
auto c = childrenVector[i];
|
||||
if (c->isFunctionDeclaration() && c->lexicalBlockIndexFunctionLocatedIn() == 0) {
|
||||
if (!canDeclareGlobalFunction(state, globalObject, c->functionName())) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Identifier '%s' has already been declared", c->functionName());
|
||||
THROW_BUILTIN_ERROR_RETURN(state, ErrorCode::TypeError, "Identifier '%s' has already been declared", c->functionName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -402,6 +402,7 @@ Value Script::execute(ExecutionState& state, bool isExecuteOnEvalFunction, bool
|
|||
}
|
||||
|
||||
testDeclareGlobalFunctions(state, m_topCodeBlock, context()->globalObject());
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
const InterpretedCodeBlock::IdentifierInfoVector& identifierVector = m_topCodeBlock->identifierInfos();
|
||||
size_t identifierVectorLen = identifierVector.size();
|
||||
|
|
@ -416,7 +417,7 @@ Value Script::execute(ExecutionState& state, bool isExecuteOnEvalFunction, bool
|
|||
InterpretedCodeBlock* child = childrenVector[i];
|
||||
if (child->isFunctionDeclaration()) {
|
||||
if (child->lexicalBlockIndexFunctionLocatedIn() == 0 && !state.context()->globalObject()->defineOwnProperty(state, child->functionName(), ObjectPropertyDescriptor(Value(), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectStructurePropertyDescriptor::EnumerablePresent)))) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::SyntaxError, "Identifier '%s' has already been declared", child->functionName());
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::SyntaxError, "Identifier '%s' has already been declared", child->functionName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -430,7 +431,7 @@ Value Script::execute(ExecutionState& state, bool isExecuteOnEvalFunction, bool
|
|||
// If envRec.HasLexicalDeclaration(name) is true, throw a SyntaxError
|
||||
for (size_t j = 0; j < identifierVectorLen; j++) {
|
||||
if (identifierVector[j].m_isVarDeclaration && identifierVector[j].m_name == globalDeclarativeRecord->at(i).m_name) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::SyntaxError, globalDeclarativeRecord->at(i).m_name.string(), false, String::emptyString, ErrorObject::Messages::DuplicatedIdentifier);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::SyntaxError, globalDeclarativeRecord->at(i).m_name.string(), false, String::emptyString, ErrorObject::Messages::DuplicatedIdentifier);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -440,7 +441,7 @@ Value Script::execute(ExecutionState& state, bool isExecuteOnEvalFunction, bool
|
|||
// If hasRestrictedGlobal is true, throw a SyntaxError exception.
|
||||
auto desc = context()->globalObject()->getOwnProperty(state, globalLexicalVector[i].m_name);
|
||||
if (desc.hasValue() && !desc.isConfigurable()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::SyntaxError, globalLexicalVector[i].m_name.string(), false, String::emptyString, "redeclaration of non-configurable global property %s");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::SyntaxError, globalLexicalVector[i].m_name.string(), false, String::emptyString, "redeclaration of non-configurable global property %s");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -450,6 +451,10 @@ Value Script::execute(ExecutionState& state, bool isExecuteOnEvalFunction, bool
|
|||
|
||||
for (size_t i = 0; i < globalLexicalVectorLen; i++) {
|
||||
codeExecutionState->lexicalEnvironment()->record()->createBinding(*codeExecutionState, globalLexicalVector[i].m_name, false, globalLexicalVector[i].m_isMutable, false);
|
||||
if (UNLIKELY(codeExecutionState->hasPendingException())) {
|
||||
state.setPendingException();
|
||||
return Value(Value::Exception);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < identifierVectorLen; i++) {
|
||||
|
|
@ -457,6 +462,10 @@ Value Script::execute(ExecutionState& state, bool isExecuteOnEvalFunction, bool
|
|||
// Step 2. If code is eval code, then let configurableBindings be true.
|
||||
if (identifierVector[i].m_isVarDeclaration) {
|
||||
globalVariableRecord->createBinding(*codeExecutionState, identifierVector[i].m_name, isExecuteOnEvalFunction, identifierVector[i].m_isMutable, true, m_topCodeBlock);
|
||||
if (UNLIKELY(codeExecutionState->hasPendingException())) {
|
||||
state.setPendingException();
|
||||
return Value(Value::Exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -502,9 +511,16 @@ Value Script::execute(ExecutionState& state, bool isExecuteOnEvalFunction, bool
|
|||
auto ep = new ExecutionPauser(state, fakeFunctionObject, newState, registerFile, m_topCodeBlock->byteCodeBlock());
|
||||
newState->setPauseSource(ep);
|
||||
ep->m_promiseCapability = PromiseObject::newPromiseCapability(*newState, newState->context()->globalObject()->promise());
|
||||
ASSERT(!newState->hasPendingException());
|
||||
resultValue = ExecutionPauser::start(*newState, newState->pauseSource(), newState->pauseSource()->sourceObject(), Value(), false, false, ExecutionPauser::StartFrom::Async);
|
||||
}
|
||||
|
||||
// check Exception
|
||||
if (UNLIKELY(resultValue.isException())) {
|
||||
ASSERT(newState->hasPendingException() || codeExecutionState->hasPendingException());
|
||||
state.setPendingException();
|
||||
}
|
||||
|
||||
return resultValue;
|
||||
}
|
||||
|
||||
|
|
@ -549,7 +565,7 @@ Value Script::executeLocal(ExecutionState& state, Value thisValue, InterpretedCo
|
|||
if (vec[i].m_isVarDeclaration) {
|
||||
auto slot = e->record()->hasBinding(state, vec[i].m_name);
|
||||
if (slot.m_isLexicallyDeclared && slot.m_index != SIZE_MAX) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::SyntaxError, vec[i].m_name.string(), false, String::emptyString, ErrorObject::Messages::DuplicatedIdentifier);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::SyntaxError, vec[i].m_name.string(), false, String::emptyString, ErrorObject::Messages::DuplicatedIdentifier);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -567,11 +583,13 @@ Value Script::executeLocal(ExecutionState& state, Value thisValue, InterpretedCo
|
|||
|
||||
if (recordToAddVariable->isGlobalEnvironmentRecord()) {
|
||||
testDeclareGlobalFunctions(state, m_topCodeBlock, context()->globalObject());
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < vecLen; i++) {
|
||||
if (vec[i].m_isVarDeclaration) {
|
||||
recordToAddVariable->createBinding(state, vec[i].m_name, inStrict ? false : true, true, true, m_topCodeBlock);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -621,6 +639,12 @@ Value Script::executeLocal(ExecutionState& state, Value thisValue, InterpretedCo
|
|||
|
||||
newState.ensureRareData()->m_codeBlock = m_topCodeBlock;
|
||||
Value resultValue = Interpreter::interpret(&newState, byteCodeBlock, reinterpret_cast<size_t>(byteCodeBlock->m_code.data()), registerFile);
|
||||
// check Exception
|
||||
if (UNLIKELY(resultValue.isException())) {
|
||||
ASSERT(newState.hasPendingException());
|
||||
state.setPendingException();
|
||||
}
|
||||
|
||||
clearStack<512>();
|
||||
|
||||
return resultValue;
|
||||
|
|
@ -792,6 +816,7 @@ Script::ModuleExecutionResult Script::moduleEvaluation(ExecutionState& state)
|
|||
|
||||
// Let capability be ! NewPromiseCapability(%Promise%).
|
||||
auto capability = PromiseObject::newPromiseCapability(state, state.context()->globalObject()->promise());
|
||||
ASSERT(!state.hasPendingException());
|
||||
// Set module.[[TopLevelCapability]] to capability.
|
||||
md->m_topLevelCapability = capability;
|
||||
|
||||
|
|
@ -1267,6 +1292,7 @@ void Script::moduleExecuteAsyncModule(ExecutionState& state)
|
|||
md->m_asyncEvaluating = true;
|
||||
// Let capability be ! NewPromiseCapability(%Promise%).
|
||||
auto capability = PromiseObject::newPromiseCapability(state, state.context()->globalObject()->promise());
|
||||
ASSERT(!state.hasPendingException());
|
||||
// Let stepsFulfilled be the steps of a CallAsyncModuleFulfilled function as specified below.
|
||||
// Let onFulfilled be CreateBuiltinFunction(stepsFulfilled, « [[Module]] »).
|
||||
// Set onFulfilled.[[Module]] to module.
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ ScriptParser::InitializeScriptResult::InitializeScriptResult()
|
|||
Script* ScriptParser::InitializeScriptResult::scriptThrowsExceptionIfParseError(ExecutionState& state)
|
||||
{
|
||||
if (!script) {
|
||||
ErrorObject::throwBuiltinError(state, parseErrorCode, parseErrorMessage->toUTF8StringData().data());
|
||||
THROW_BUILTIN_ERROR_RETURN_NULL(state, parseErrorCode, parseErrorMessage->toUTF8StringData().data());
|
||||
}
|
||||
|
||||
return script.value();
|
||||
|
|
@ -484,6 +484,7 @@ void ScriptParser::generateFunctionByteCode(ExecutionState& state, InterpretedCo
|
|||
auto parseResult = esprima::parseSingleFunction(m_context, codeBlock, stackSizeRemain);
|
||||
|
||||
if (UNLIKELY(!!parseResult.second)) {
|
||||
RELEASE_ASSERT_NOT_REACHED();
|
||||
esprima::Error* orgError = parseResult.second;
|
||||
// reset ASTAllocator
|
||||
m_context->astAllocator().reset();
|
||||
|
|
@ -491,6 +492,7 @@ void ScriptParser::generateFunctionByteCode(ExecutionState& state, InterpretedCo
|
|||
|
||||
auto str = orgError->message->toUTF8StringData();
|
||||
delete orgError;
|
||||
// ignore exception
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::SyntaxError, str.data());
|
||||
RELEASE_ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
|
@ -503,9 +505,11 @@ void ScriptParser::generateFunctionByteCode(ExecutionState& state, InterpretedCo
|
|||
try {
|
||||
codeBlock->m_byteCodeBlock = ByteCodeGenerator::generateByteCode(state.context(), codeBlock, functionNode);
|
||||
} catch (const char* message) {
|
||||
RELEASE_ASSERT_NOT_REACHED();
|
||||
// reset ASTAllocator
|
||||
m_context->astAllocator().reset();
|
||||
GC_enable();
|
||||
// ignore exception
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::SyntaxError, message);
|
||||
RELEASE_ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,9 +42,11 @@ static void ArgumentsObjectNativeSetter(ExecutionState& state, Object* self, con
|
|||
ASSERT(!info.m_needToAllocateOnStack);
|
||||
if (info.m_indexForIndexedStorage == SIZE_MAX) {
|
||||
targetRecord->setMutableBinding(state, name, setterInputData);
|
||||
ASSERT(!state.hasPendingException());
|
||||
return;
|
||||
}
|
||||
targetRecord->setHeapValueByIndex(state, info.m_indexForIndexedStorage, setterInputData);
|
||||
ASSERT(!state.hasPendingException());
|
||||
}
|
||||
|
||||
ArgumentsObject::ArgumentsObject(ExecutionState& state, Object* proto, ScriptFunctionObject* sourceFunctionObject, size_t argc, Value* argv, FunctionEnvironmentRecord* environmentRecordWillArgumentsObjectBeLocatedIn, bool isMapped)
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ public:
|
|||
ALWAYS_INLINE void throwTypeErrorIfDetached(ExecutionState& state)
|
||||
{
|
||||
if (UNLIKELY(isDetachedBuffer())) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().TypedArray.string(), true, state.context()->staticStrings().constructor.string(), ErrorObject::Messages::GlobalObject_DetachedBuffer);
|
||||
THROW_BUILTIN_ERROR_RETURN(state, ErrorCode::TypeError, state.context()->staticStrings().TypedArray.string(), true, state.context()->staticStrings().constructor.string(), ErrorObject::Messages::GlobalObject_DetachedBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,9 +33,10 @@ ArrayBufferObject* ArrayBufferObject::allocateArrayBuffer(ExecutionState& state,
|
|||
Object* proto = Object::getPrototypeFromConstructor(state, constructor, [](ExecutionState& state, Context* constructorRealm) -> Object* {
|
||||
return constructorRealm->globalObject()->arrayBufferPrototype();
|
||||
});
|
||||
RETURN_NULL_IF_PENDING_EXCEPTION
|
||||
|
||||
if (UNLIKELY(byteLength >= ArrayBuffer::maxArrayBufferSize)) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, state.context()->staticStrings().ArrayBuffer.string(), false, String::emptyString, ErrorObject::Messages::GlobalObject_InvalidArrayBufferSize);
|
||||
THROW_BUILTIN_ERROR_RETURN_NULL(state, ErrorCode::RangeError, state.context()->staticStrings().ArrayBuffer.string(), false, String::emptyString, ErrorObject::Messages::GlobalObject_InvalidArrayBufferSize);
|
||||
}
|
||||
|
||||
ArrayBufferObject* obj = new ArrayBufferObject(state, proto);
|
||||
|
|
@ -44,7 +45,7 @@ ArrayBufferObject* ArrayBufferObject::allocateArrayBuffer(ExecutionState& state,
|
|||
ASSERT(byteLength <= maxByteLength.value());
|
||||
uint64_t maxLength = maxByteLength.value();
|
||||
if (UNLIKELY(maxLength >= ArrayBuffer::maxArrayBufferSize)) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, state.context()->staticStrings().ArrayBuffer.string(), false, String::emptyString, ErrorObject::Messages::GlobalObject_InvalidArrayBufferSize);
|
||||
THROW_BUILTIN_ERROR_RETURN_NULL(state, ErrorCode::RangeError, state.context()->staticStrings().ArrayBuffer.string(), false, String::emptyString, ErrorObject::Messages::GlobalObject_InvalidArrayBufferSize);
|
||||
}
|
||||
|
||||
// allocate default resizable non-shared BackingStore
|
||||
|
|
@ -63,7 +64,9 @@ ArrayBufferObject* ArrayBufferObject::cloneArrayBuffer(ExecutionState& state, Ar
|
|||
ASSERT(constructor->isConstructor());
|
||||
|
||||
ArrayBufferObject* targetBuffer = ArrayBufferObject::allocateArrayBuffer(state, constructor, srcLength);
|
||||
RETURN_NULL_IF_PENDING_EXCEPTION
|
||||
srcBuffer->throwTypeErrorIfDetached(state);
|
||||
RETURN_NULL_IF_PENDING_EXCEPTION
|
||||
|
||||
targetBuffer->fillData(srcBuffer->data() + srcByteOffset, srcLength);
|
||||
|
||||
|
|
|
|||
|
|
@ -74,10 +74,11 @@ ArrayObject::ArrayObject(ExecutionState& state, Object* proto, const uint64_t& s
|
|||
: ArrayObject(state, proto)
|
||||
{
|
||||
if (UNLIKELY(size > ((1LL << 32LL) - 1LL))) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, ErrorObject::Messages::GlobalObject_InvalidArrayLength);
|
||||
THROW_BUILTIN_ERROR_RETURN(state, ErrorCode::RangeError, ErrorObject::Messages::GlobalObject_InvalidArrayLength);
|
||||
}
|
||||
|
||||
setArrayLength(state, size, true, shouldConsiderHole);
|
||||
ASSERT(!state.hasPendingException());
|
||||
}
|
||||
|
||||
ArrayObject::ArrayObject(ExecutionState& state, const Value* src, const uint64_t& size)
|
||||
|
|
@ -149,7 +150,7 @@ bool ArrayObject::defineOwnProperty(ExecutionState& state, const ObjectPropertyN
|
|||
newLen = desc.value().toUint32(state);
|
||||
// If newLen is not equal to ToNumber( Desc.[[Value]]), throw a RangeError exception.
|
||||
if (newLen != desc.value().toNumber(state)) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, ErrorObject::Messages::GlobalObject_InvalidArrayLength);
|
||||
THROW_BUILTIN_ERROR_RETURN_ZERO(state, ErrorCode::RangeError, ErrorObject::Messages::GlobalObject_InvalidArrayLength);
|
||||
}
|
||||
}
|
||||
if (!isLengthPropertyWritable() && desc.isValuePresent() && m_arrayLength != newLen) {
|
||||
|
|
@ -211,6 +212,7 @@ bool ArrayObject::defineOwnProperty(ExecutionState& state, const ObjectPropertyN
|
|||
goto NonFastPath;
|
||||
}
|
||||
if (UNLIKELY(!setArrayLength(state, idx + 1)) || UNLIKELY(!isFastModeArray())) {
|
||||
RETURN_ZERO_IF_PENDING_EXCEPTION
|
||||
goto NonFastPath;
|
||||
}
|
||||
}
|
||||
|
|
@ -310,6 +312,7 @@ void ArrayObject::sort(ExecutionState& state, int64_t length, const std::functio
|
|||
|
||||
if (arrayLength(state) != orgLength) {
|
||||
setArrayLength(state, orgLength);
|
||||
ASSERT(!state.hasPendingException());
|
||||
}
|
||||
|
||||
if (isFastModeArray()) {
|
||||
|
|
@ -358,6 +361,7 @@ void ArrayObject::convertIntoNonFastMode(ExecutionState& state)
|
|||
for (size_t i = 0; i < length; i++) {
|
||||
if (!tempFastModeData[i].isEmpty()) {
|
||||
Object::defineOwnPropertyThrowsException(state, ObjectPropertyName(state, Value(i)), ObjectPropertyDescriptor(tempFastModeData[i], ObjectPropertyDescriptor::AllPresent));
|
||||
ASSERT(!state.hasPendingException());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -381,7 +385,7 @@ bool ArrayObject::setArrayLength(ExecutionState& state, const Value& newLength)
|
|||
uint32_t newLen = newLength.toUint32(state);
|
||||
// If newLen is not equal to ToNumber( Desc.[[Value]]), throw a RangeError exception.
|
||||
if (newLen != newLength.toNumber(state)) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, ErrorObject::Messages::GlobalObject_InvalidArrayLength);
|
||||
THROW_BUILTIN_ERROR_RETURN_ZERO(state, ErrorCode::RangeError, ErrorObject::Messages::GlobalObject_InvalidArrayLength);
|
||||
}
|
||||
|
||||
bool ret;
|
||||
|
|
@ -604,6 +608,7 @@ bool ArrayObject::setIndexedProperty(ExecutionState& state, const Value& propert
|
|||
return false;
|
||||
}
|
||||
if (UNLIKELY(!setArrayLength(state, idx + 1)) || UNLIKELY(!isFastModeArray())) {
|
||||
RETURN_ZERO_IF_PENDING_EXCEPTION
|
||||
return set(state, ObjectPropertyName(state, property), value, this);
|
||||
}
|
||||
// fast, non-fast mode can be changed while changing length
|
||||
|
|
@ -679,14 +684,18 @@ std::pair<Value, bool> ArrayIteratorObject::advance(ExecutionState& state)
|
|||
if (a->isTypedArrayObject()) {
|
||||
// If IsDetachedBuffer(a.[[ViewedArrayBuffer]]) is true, throw a TypeError exception.
|
||||
if (a->asArrayBufferView()->buffer()->isDetachedBuffer()) {
|
||||
// FIXME THROW
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().ArrayIterator.string(), true, state.context()->staticStrings().next.string(), ErrorObject::Messages::GlobalObject_DetachedBuffer);
|
||||
return std::make_pair(Value(), false);
|
||||
return std::make_pair(Value(Value::Exception), false);
|
||||
}
|
||||
// Let len be a.[[ArrayLength]].
|
||||
len = a->asArrayBufferView()->arrayLength();
|
||||
} else {
|
||||
// Let len be ? ToLength(? Get(a, "length")).
|
||||
len = a->length(state);
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
return std::make_pair(Value(Value::Exception), false);
|
||||
}
|
||||
}
|
||||
|
||||
// If index ≥ len, then
|
||||
|
|
|
|||
|
|
@ -90,6 +90,7 @@ Value AsyncGeneratorObject::asyncGeneratorEnqueue(ExecutionState& state, const V
|
|||
{
|
||||
// Let promiseCapability be ! NewPromiseCapability(%Promise%).
|
||||
PromiseReaction::Capability promiseCapability = PromiseObject::newPromiseCapability(state, state.context()->globalObject()->promise());
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// If Type(generator) is not Object, or if generator does not have an [[AsyncGeneratorState]] internal slot, then
|
||||
if (!generator.isObject() || !generator.asObject()->isAsyncGeneratorObject()) {
|
||||
// Let badGeneratorError be a newly created TypeError object.
|
||||
|
|
@ -97,6 +98,7 @@ Value AsyncGeneratorObject::asyncGeneratorEnqueue(ExecutionState& state, const V
|
|||
// Perform ! Call(promiseCapability.[[Reject]], undefined, « badGeneratorError »).
|
||||
Value argv(badGeneratorError);
|
||||
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &argv);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Return promiseCapability.[[Promise]].
|
||||
return promiseCapability.m_promise;
|
||||
}
|
||||
|
|
@ -114,6 +116,7 @@ Value AsyncGeneratorObject::asyncGeneratorEnqueue(ExecutionState& state, const V
|
|||
if (generatorObject->asyncGeneratorState() != AsyncGeneratorObject::Executing) {
|
||||
// Perform ! AsyncGeneratorResumeNext(generator).
|
||||
AsyncGeneratorObject::asyncGeneratorResumeNext(state, generatorObject);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
}
|
||||
// Return promiseCapability.[[Promise]].
|
||||
return promiseCapability.m_promise;
|
||||
|
|
@ -158,7 +161,9 @@ Value AsyncGeneratorObject::asyncGeneratorResumeNext(ExecutionState& state, Asyn
|
|||
// Set generator.[[AsyncGeneratorState]] to "awaiting-return".
|
||||
generator->m_asyncGeneratorState = AsyncGeneratorObject::AwaitingReturn;
|
||||
// Let promise be ? PromiseResolve(%Promise%, « completion.[[Value]] »).
|
||||
auto promise = PromiseObject::promiseResolve(state, state.context()->globalObject()->promise(), next.m_value)->asPromiseObject();
|
||||
auto promiseObj = PromiseObject::promiseResolve(state, state.context()->globalObject()->promise(), next.m_value);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
auto promise = promiseObj->asPromiseObject();
|
||||
// Let stepsFulfilled be the algorithm steps defined in AsyncGeneratorResumeNext Return Processor Fulfilled Functions.
|
||||
// Let onFulfilled be CreateBuiltinFunction(stepsFulfilled, « [[Generator]] »).
|
||||
// Set onFulfilled.[[Generator]] to generator.
|
||||
|
|
@ -177,6 +182,7 @@ Value AsyncGeneratorObject::asyncGeneratorResumeNext(ExecutionState& state, Asyn
|
|||
// Assert: completion.[[Type]] is throw.
|
||||
// Perform ! AsyncGeneratorReject(generator, completion.[[Value]]).
|
||||
AsyncGeneratorObject::asyncGeneratorReject(state, generator, next.m_value);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Return undefined.
|
||||
return Value();
|
||||
}
|
||||
|
|
@ -198,6 +204,7 @@ Value AsyncGeneratorObject::asyncGeneratorResumeNext(ExecutionState& state, Asyn
|
|||
bool isAbruptReturn = next.m_operationType == AsyncGeneratorObject::AsyncGeneratorEnqueueType::Return;
|
||||
bool isAbruptThrow = next.m_operationType == AsyncGeneratorObject::AsyncGeneratorEnqueueType::Throw;
|
||||
ExecutionPauser::start(state, &generator->m_executionPauser, generator, next.m_value, isAbruptReturn, isAbruptThrow, ExecutionPauser::StartFrom::AsyncGenerator);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Assert: result is never an abrupt completion.
|
||||
// Assert: When we return here, genContext has already been removed from the execution context stack and callerContext is the currently running execution context.
|
||||
// Return undefined.
|
||||
|
|
@ -221,8 +228,10 @@ Value AsyncGeneratorObject::asyncGeneratorResolve(ExecutionState& state, AsyncGe
|
|||
Value iteratorResult = IteratorObject::createIterResultObject(state, value, done);
|
||||
// Perform ! Call(promiseCapability.[[Resolve]], undefined, « iteratorResult »).
|
||||
Object::call(state, promiseCapability.m_resolveFunction, Value(), 1, &iteratorResult);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Perform ! AsyncGeneratorResumeNext(generator).
|
||||
AsyncGeneratorObject::asyncGeneratorResumeNext(state, generator);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Return undefined.
|
||||
return Value();
|
||||
}
|
||||
|
|
@ -242,8 +251,10 @@ Value AsyncGeneratorObject::asyncGeneratorReject(ExecutionState& state, AsyncGen
|
|||
auto promiseCapability = next.m_capability;
|
||||
// Perform ! Call(promiseCapability.[[Reject]], undefined, « exception »).
|
||||
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &exception);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Perform ! AsyncGeneratorResumeNext(generator).
|
||||
AsyncGeneratorObject::asyncGeneratorResumeNext(state, generator);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Return undefined.
|
||||
return Value();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -246,8 +246,7 @@ void BigInt::throwBFException(ExecutionState& state, int status)
|
|||
} else {
|
||||
message = ErrorObject::Messages::Overflow;
|
||||
}
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, message);
|
||||
return;
|
||||
THROW_BUILTIN_ERROR_RETURN(state, ErrorCode::RangeError, message);
|
||||
}
|
||||
|
||||
String* BigInt::toString(int radix)
|
||||
|
|
|
|||
|
|
@ -88,6 +88,8 @@ Value BoundFunctionObject::construct(ExecutionState& state, const size_t calledA
|
|||
}
|
||||
|
||||
// Return Construct(target, args, newTarget).
|
||||
return Object::construct(state, m_boundTargetFunction, mergedArgc, mergedArgv, newTarget).toObject(state);
|
||||
Value result = Object::construct(state, m_boundTargetFunction, mergedArgc, mergedArgv, newTarget);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
return result.toObject(state);
|
||||
}
|
||||
} // namespace Escargot
|
||||
|
|
|
|||
|
|
@ -49,19 +49,20 @@ public:
|
|||
{
|
||||
double numberIndex = index.toIndex(state);
|
||||
if (numberIndex == Value::InvalidIndexValue) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, state.context()->staticStrings().DataView.string(), false, String::emptyString, ErrorObject::Messages::GlobalObject_InvalidArrayBufferOffset);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::RangeError, state.context()->staticStrings().DataView.string(), false, String::emptyString, ErrorObject::Messages::GlobalObject_InvalidArrayBufferOffset);
|
||||
}
|
||||
|
||||
bool isLittleEndian = _isLittleEndian.toBoolean(state);
|
||||
ArrayBuffer* buffer = this->buffer();
|
||||
buffer->throwTypeErrorIfDetached(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
size_t viewOffset = byteOffset();
|
||||
size_t viewSize = byteLength();
|
||||
size_t elementSize = TypedArrayHelper::elementSize(type);
|
||||
|
||||
if (numberIndex + elementSize > viewSize) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, state.context()->staticStrings().DataView.string(), false, String::emptyString, ErrorObject::Messages::GlobalObject_RangeError);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::RangeError, state.context()->staticStrings().DataView.string(), false, String::emptyString, ErrorObject::Messages::GlobalObject_RangeError);
|
||||
}
|
||||
|
||||
size_t bufferIndex = numberIndex + viewOffset;
|
||||
|
|
@ -73,22 +74,24 @@ public:
|
|||
{
|
||||
double numberIndex = index.toIndex(state);
|
||||
if (numberIndex == Value::InvalidIndexValue) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, state.context()->staticStrings().DataView.string(), false, String::emptyString, ErrorObject::Messages::GlobalObject_InvalidArrayBufferOffset);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::RangeError, state.context()->staticStrings().DataView.string(), false, String::emptyString, ErrorObject::Messages::GlobalObject_InvalidArrayBufferOffset);
|
||||
}
|
||||
|
||||
auto numericValue = val.toNumeric(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
UNUSED_VARIABLE(numericValue);
|
||||
|
||||
bool isLittleEndian = _isLittleEndian.toBoolean(state);
|
||||
ArrayBuffer* buffer = this->buffer();
|
||||
buffer->throwTypeErrorIfDetached(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
size_t viewOffset = byteOffset();
|
||||
size_t viewSize = byteLength();
|
||||
size_t elementSize = TypedArrayHelper::elementSize(type);
|
||||
|
||||
if (numberIndex + elementSize > viewSize) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, state.context()->staticStrings().DataView.string(), false, String::emptyString, ErrorObject::Messages::GlobalObject_RangeError);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::RangeError, state.context()->staticStrings().DataView.string(), false, String::emptyString, ErrorObject::Messages::GlobalObject_RangeError);
|
||||
}
|
||||
|
||||
size_t bufferIndex = numberIndex + viewOffset;
|
||||
|
|
|
|||
|
|
@ -208,10 +208,12 @@ void DateObject::setTimeValue(time64_t t)
|
|||
void DateObject::setTimeValue(ExecutionState& state, const Value& v)
|
||||
{
|
||||
Value pv = v.toPrimitive(state);
|
||||
RETURN_IF_PENDING_EXCEPTION
|
||||
if (pv.isNumber()) {
|
||||
setTimeValue(DateObject::timeClip(state, pv.asNumber()));
|
||||
} else {
|
||||
String* istr = v.toString(state);
|
||||
RETURN_IF_PENDING_EXCEPTION
|
||||
setTimeValue(parseStringToDate(state, istr));
|
||||
}
|
||||
}
|
||||
|
|
@ -1355,7 +1357,7 @@ String* DateObject::toISOString(ExecutionState& state)
|
|||
}
|
||||
return new ASCIIString(buffer);
|
||||
} else {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, state.context()->staticStrings().Date.string(), true, state.context()->staticStrings().toISOString.string(), ErrorObject::Messages::GlobalObject_InvalidDate);
|
||||
THROW_BUILTIN_ERROR_RETURN_NULL(state, ErrorCode::RangeError, state.context()->staticStrings().Date.string(), true, state.context()->staticStrings().toISOString.string(), ErrorObject::Messages::GlobalObject_InvalidDate);
|
||||
}
|
||||
RELEASE_ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -124,6 +124,7 @@ void EnumerateObjectWithDestruction::fillRestElement(ExecutionState& state, Obje
|
|||
// check unmarked key and put rest properties
|
||||
if (!key.isEmpty()) {
|
||||
value = m_object->getIndexedProperty(state, key).value(state, m_object);
|
||||
RETURN_IF_PENDING_EXCEPTION
|
||||
result->setIndexedProperty(state, key, value);
|
||||
}
|
||||
}
|
||||
|
|
@ -225,7 +226,8 @@ void EnumerateObjectWithIteration::executeEnumeration(ExecutionState& state, Enc
|
|||
|
||||
// v8 throw exception when there is too many things on prototype chain
|
||||
if (UNLIKELY(m_hiddenClassChain.size() > 1024 * 128)) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, "Maximum call stack size exceeded");
|
||||
RELEASE_ASSERT_NOT_REACHED();
|
||||
//ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, "Maximum call stack size exceeded");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ void GlobalEnvironmentRecord::createBinding(ExecutionState& state, const AtomicS
|
|||
{
|
||||
for (size_t i = 0; i < m_globalDeclarativeRecord->size(); i++) {
|
||||
if (m_globalDeclarativeRecord->at(i).m_name == name) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::SyntaxError, name.string(), false, String::emptyString, ErrorObject::Messages::DuplicatedIdentifier);
|
||||
THROW_BUILTIN_ERROR_RETURN(state, ErrorCode::SyntaxError, name.string(), false, String::emptyString, ErrorObject::Messages::DuplicatedIdentifier);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -94,7 +94,9 @@ EnvironmentRecord::GetBindingValueResult GlobalEnvironmentRecord::getBindingValu
|
|||
for (size_t i = 0; i < m_globalDeclarativeRecord->size(); i++) {
|
||||
if (m_globalDeclarativeRecord->at(i).m_name == name) {
|
||||
if (UNLIKELY(m_globalDeclarativeStorage->at(i).isEmpty())) {
|
||||
// Return Exception Done!
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::ReferenceError, name.string(), false, String::emptyString, ErrorObject::Messages::IsNotInitialized);
|
||||
return EnvironmentRecord::GetBindingValueResult();
|
||||
}
|
||||
return EnvironmentRecord::GetBindingValueResult(true, m_globalDeclarativeStorage->at(i));
|
||||
}
|
||||
|
|
@ -112,6 +114,8 @@ void GlobalEnvironmentRecord::setMutableBinding(ExecutionState& state, const Ato
|
|||
for (size_t i = 0; i < m_globalDeclarativeRecord->size(); i++) {
|
||||
if (m_globalDeclarativeRecord->at(i).m_name == name) {
|
||||
if (UNLIKELY(m_globalDeclarativeStorage->at(i).isEmpty())) {
|
||||
// ignore return Exception
|
||||
ASSERT_NOT_REACHED();
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::ReferenceError, name.string(), false, String::emptyString, ErrorObject::Messages::IsNotInitialized);
|
||||
}
|
||||
m_globalDeclarativeStorage->at(i) = V;
|
||||
|
|
@ -120,6 +124,7 @@ void GlobalEnvironmentRecord::setMutableBinding(ExecutionState& state, const Ato
|
|||
}
|
||||
|
||||
m_globalObject->setThrowsExceptionWhenStrictMode(state, name, V, m_globalObject);
|
||||
ASSERT(!state.hasPendingException());
|
||||
}
|
||||
|
||||
void GlobalEnvironmentRecord::setMutableBindingByBindingSlot(ExecutionState& state, const BindingSlot& slot, const AtomicString& name, const Value& V)
|
||||
|
|
@ -128,12 +133,12 @@ void GlobalEnvironmentRecord::setMutableBindingByBindingSlot(ExecutionState& sta
|
|||
if (slot.m_index != SIZE_MAX - 1) {
|
||||
// TDZ check
|
||||
if (UNLIKELY(m_globalDeclarativeStorage->at(slot.m_index).isEmpty())) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::ReferenceError, name.string(), false, String::emptyString, ErrorObject::Messages::IsNotInitialized);
|
||||
THROW_BUILTIN_ERROR_RETURN(state, ErrorCode::ReferenceError, name.string(), false, String::emptyString, ErrorObject::Messages::IsNotInitialized);
|
||||
}
|
||||
|
||||
// Storing to const variable check
|
||||
if (UNLIKELY(!m_globalDeclarativeRecord->at(slot.m_index).m_isMutable)) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::AssignmentToConstantVariable, name);
|
||||
THROW_BUILTIN_ERROR_RETURN(state, ErrorCode::TypeError, ErrorObject::Messages::AssignmentToConstantVariable, name);
|
||||
}
|
||||
m_globalDeclarativeStorage->at(slot.m_index) = V;
|
||||
return;
|
||||
|
|
@ -204,7 +209,7 @@ void DeclarativeEnvironmentRecordNotIndexed::createBinding(ExecutionState& state
|
|||
auto hasBindingResult = hasBinding(state, name);
|
||||
if (UNLIKELY(hasBindingResult.m_index != SIZE_MAX)) {
|
||||
if (!m_recordVector[hasBindingResult.m_index].m_isVarDeclaration || !isVarDeclaration) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::SyntaxError, name.string(), false, String::emptyString, ErrorObject::Messages::DuplicatedIdentifier);
|
||||
THROW_BUILTIN_ERROR_RETURN(state, ErrorCode::SyntaxError, name.string(), false, String::emptyString, ErrorObject::Messages::DuplicatedIdentifier);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
@ -227,7 +232,9 @@ EnvironmentRecord::GetBindingValueResult DeclarativeEnvironmentRecordNotIndexed:
|
|||
for (size_t i = 0; i < len; i++) {
|
||||
if (m_recordVector[i].m_name == name) {
|
||||
if (UNLIKELY(m_heapStorage[i].isEmpty())) {
|
||||
// Return Exception Done!
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::ReferenceError, name.string(), false, String::emptyString, ErrorObject::Messages::IsNotInitialized);
|
||||
return GetBindingValueResult();
|
||||
}
|
||||
return EnvironmentRecord::GetBindingValueResult(m_heapStorage[i]);
|
||||
}
|
||||
|
|
@ -241,10 +248,14 @@ void DeclarativeEnvironmentRecordNotIndexed::setMutableBinding(ExecutionState& s
|
|||
for (size_t i = 0; i < len; i++) {
|
||||
if (m_recordVector[i].m_name == name) {
|
||||
if (UNLIKELY(m_heapStorage[i].isEmpty())) {
|
||||
// ignore exception
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::ReferenceError, name.string(), false, String::emptyString, ErrorObject::Messages::IsNotInitialized);
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
if (UNLIKELY(!m_recordVector[i].m_isMutable)) {
|
||||
// ignore exception
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::AssignmentToConstantVariable, name);
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
m_heapStorage[i] = V;
|
||||
return;
|
||||
|
|
@ -257,12 +268,12 @@ void DeclarativeEnvironmentRecordNotIndexed::setMutableBindingByBindingSlot(Exec
|
|||
{
|
||||
// TDZ check
|
||||
if (UNLIKELY(m_heapStorage[slot.m_index].isEmpty())) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::ReferenceError, name.string(), false, String::emptyString, ErrorObject::Messages::IsNotInitialized);
|
||||
THROW_BUILTIN_ERROR_RETURN(state, ErrorCode::ReferenceError, name.string(), false, String::emptyString, ErrorObject::Messages::IsNotInitialized);
|
||||
}
|
||||
|
||||
// Storing to const variable check
|
||||
if (UNLIKELY(!m_recordVector[slot.m_index].m_isMutable)) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::AssignmentToConstantVariable, name);
|
||||
THROW_BUILTIN_ERROR_RETURN(state, ErrorCode::TypeError, ErrorObject::Messages::AssignmentToConstantVariable, name);
|
||||
}
|
||||
m_heapStorage[slot.m_index] = v;
|
||||
}
|
||||
|
|
@ -292,7 +303,7 @@ void FunctionEnvironmentRecordOnHeap<canBindThisValue, hasNewTarget>::setMutable
|
|||
const auto& recordInfo = FunctionEnvironmentRecordWithExtraData<canBindThisValue, hasNewTarget>::functionObject()->interpretedCodeBlock()->identifierInfos();
|
||||
if (UNLIKELY(!recordInfo[slot.m_index].m_isMutable)) {
|
||||
if (state.inStrictMode()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::AssignmentToConstantVariable, name);
|
||||
THROW_BUILTIN_ERROR_RETURN(state, ErrorCode::TypeError, ErrorObject::Messages::AssignmentToConstantVariable, name);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
@ -312,7 +323,7 @@ void FunctionEnvironmentRecordOnHeapWithInlineStorage<canBindThisValue, hasNewTa
|
|||
const auto& recordInfo = FunctionEnvironmentRecordWithExtraData<canBindThisValue, hasNewTarget>::functionObject()->interpretedCodeBlock()->identifierInfos();
|
||||
if (UNLIKELY(!recordInfo[slot.m_index].m_isMutable)) {
|
||||
if (state.inStrictMode()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::AssignmentToConstantVariable, name);
|
||||
THROW_BUILTIN_ERROR_RETURN(state, ErrorCode::TypeError, ErrorObject::Messages::AssignmentToConstantVariable, name);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
@ -378,8 +389,11 @@ void FunctionEnvironmentRecordNotIndexed<canBindThisValue, hasNewTarget>::setMut
|
|||
for (size_t i = 0; i < len; i++) {
|
||||
if (m_recordVector[i].m_name == name) {
|
||||
if (UNLIKELY(!m_recordVector[i].m_isMutable)) {
|
||||
if (state.inStrictMode())
|
||||
if (state.inStrictMode()) {
|
||||
// ignore exception
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::AssignmentToConstantVariable, name);
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
return;
|
||||
}
|
||||
m_heapStorage[i] = V;
|
||||
|
|
@ -395,7 +409,7 @@ void FunctionEnvironmentRecordNotIndexed<canBindThisValue, hasNewTarget>::setMut
|
|||
// Storing to const variable check only (TDZ check is already done by bytecode generation)
|
||||
if (UNLIKELY(!m_recordVector[slot.m_index].m_isMutable)) {
|
||||
if (state.inStrictMode())
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::AssignmentToConstantVariable, name);
|
||||
THROW_BUILTIN_ERROR_RETURN(state, ErrorCode::TypeError, ErrorObject::Messages::AssignmentToConstantVariable, name);
|
||||
return;
|
||||
}
|
||||
m_heapStorage[slot.m_index] = v;
|
||||
|
|
@ -462,7 +476,7 @@ void ModuleEnvironmentRecord::createBinding(ExecutionState& state, const AtomicS
|
|||
auto hasBindingResult = hasBinding(state, name);
|
||||
if (UNLIKELY(hasBindingResult.m_index != SIZE_MAX)) {
|
||||
if (!m_moduleBindings[hasBindingResult.m_index].m_isVarDeclaration || !isVarDeclaration) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::SyntaxError, name.string(), false, String::emptyString, ErrorObject::Messages::DuplicatedIdentifier);
|
||||
THROW_BUILTIN_ERROR_RETURN(state, ErrorCode::SyntaxError, name.string(), false, String::emptyString, ErrorObject::Messages::DuplicatedIdentifier);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -251,9 +251,15 @@ public:
|
|||
// we check conditions same as hasBinding for performance reason
|
||||
// directly call getBindingValue instead of checking the result of hasBinding in advance
|
||||
Value unscopables = m_bindingObject->get(state, ObjectPropertyName(state.context()->vmInstance()->globalSymbols().unscopables)).value(state, m_bindingObject);
|
||||
if (UNLIKELY(unscopables.isObject() && unscopables.asObject()->get(state, propertyName).value(state, unscopables).toBoolean(state))) {
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
return GetBindingValueResult();
|
||||
}
|
||||
if (UNLIKELY(unscopables.isObject())) {
|
||||
Value obj = unscopables.asObject()->get(state, propertyName).value(state, unscopables);
|
||||
if (state.hasPendingException() || obj.toBoolean(state)) {
|
||||
return GetBindingValueResult();
|
||||
}
|
||||
}
|
||||
|
||||
return GetBindingValueResult(result.value(state, propertyName, m_bindingObject));
|
||||
}
|
||||
|
|
@ -440,6 +446,7 @@ public:
|
|||
virtual void setHeapValueByIndex(ExecutionState& state, const size_t idx, const Value& v) override
|
||||
{
|
||||
if (UNLIKELY(m_heapStorage[idx].isEmpty())) {
|
||||
// ignore exception
|
||||
throwReferenceError(state, idx);
|
||||
}
|
||||
m_heapStorage[idx] = v;
|
||||
|
|
@ -473,6 +480,7 @@ public:
|
|||
// TDZ check only (every indexed const variables are checked on bytecode generation time)
|
||||
if (UNLIKELY(m_heapStorage[slot.m_index].isEmpty())) {
|
||||
throwReferenceError(state, slot.m_index);
|
||||
RETURN_IF_PENDING_EXCEPTION
|
||||
}
|
||||
m_heapStorage[slot.m_index] = v;
|
||||
}
|
||||
|
|
@ -481,6 +489,7 @@ public:
|
|||
{
|
||||
if (UNLIKELY(m_heapStorage[idx].isEmpty())) {
|
||||
throwReferenceError(state, idx);
|
||||
RETURN_IF_PENDING_EXCEPTION
|
||||
}
|
||||
m_heapStorage[idx] = v;
|
||||
}
|
||||
|
|
@ -495,6 +504,7 @@ public:
|
|||
auto v = m_heapStorage[idx];
|
||||
if (UNLIKELY(v.isEmpty())) {
|
||||
throwReferenceError(state, idx);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
|
@ -506,7 +516,7 @@ public:
|
|||
for (size_t i = 0; i < v.size(); i++) {
|
||||
if (!v[i].m_needToAllocateOnStack) {
|
||||
if (cnt == idx) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::ReferenceError, v[i].m_name.string(), false, String::emptyString, ErrorObject::Messages::IsNotInitialized);
|
||||
THROW_BUILTIN_ERROR_RETURN(state, ErrorCode::ReferenceError, v[i].m_name.string(), false, String::emptyString, ErrorObject::Messages::IsNotInitialized);
|
||||
}
|
||||
cnt++;
|
||||
}
|
||||
|
|
@ -676,7 +686,7 @@ struct FunctionEnvironmentRecordPiece<true, false> {
|
|||
void bindThisValue(ExecutionState& state, const Value& thisValue)
|
||||
{
|
||||
if (!m_thisValue.isEmpty()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::ReferenceError, ErrorObject::Messages::Initialized_This_Binding);
|
||||
THROW_BUILTIN_ERROR_RETURN(state, ErrorCode::ReferenceError, ErrorObject::Messages::Initialized_This_Binding);
|
||||
}
|
||||
|
||||
m_thisValue = thisValue;
|
||||
|
|
@ -685,7 +695,7 @@ struct FunctionEnvironmentRecordPiece<true, false> {
|
|||
Value getThisBinding(ExecutionState& state)
|
||||
{
|
||||
if (m_thisValue.isEmpty()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::ReferenceError, ErrorObject::Messages::UnInitialized_This_Binding);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::ReferenceError, ErrorObject::Messages::UnInitialized_This_Binding);
|
||||
}
|
||||
return m_thisValue;
|
||||
}
|
||||
|
|
@ -746,7 +756,7 @@ struct FunctionEnvironmentRecordPiece<true, true> {
|
|||
void bindThisValue(ExecutionState& state, const Value& thisValue)
|
||||
{
|
||||
if (!m_thisValue.isEmpty()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::ReferenceError, ErrorObject::Messages::Initialized_This_Binding);
|
||||
THROW_BUILTIN_ERROR_RETURN(state, ErrorCode::ReferenceError, ErrorObject::Messages::Initialized_This_Binding);
|
||||
}
|
||||
|
||||
m_thisValue = thisValue;
|
||||
|
|
@ -755,7 +765,7 @@ struct FunctionEnvironmentRecordPiece<true, true> {
|
|||
Value getThisBinding(ExecutionState& state)
|
||||
{
|
||||
if (m_thisValue.isEmpty()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::ReferenceError, ErrorObject::Messages::UnInitialized_This_Binding);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::ReferenceError, ErrorObject::Messages::UnInitialized_This_Binding);
|
||||
}
|
||||
return m_thisValue;
|
||||
}
|
||||
|
|
@ -1257,6 +1267,7 @@ protected:
|
|||
void readCheck(ExecutionState& state, const size_t i)
|
||||
{
|
||||
if (UNLIKELY(m_moduleBindings[i].m_value.isEmpty())) {
|
||||
// ignore exception
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::ReferenceError, m_moduleBindings[i].m_localName.string(), false, String::emptyString, ErrorObject::Messages::IsNotInitialized);
|
||||
}
|
||||
}
|
||||
|
|
@ -1264,10 +1275,12 @@ protected:
|
|||
void writeCheck(ExecutionState& state, const size_t i)
|
||||
{
|
||||
if (UNLIKELY(!m_moduleBindings[i].m_isMutable)) {
|
||||
// ignore exception
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::AssignmentToConstantVariable, m_moduleBindings[i].m_localName);
|
||||
}
|
||||
|
||||
if (UNLIKELY(!m_moduleBindings[i].m_isVarDeclaration && m_moduleBindings[i].m_value.isEmpty())) {
|
||||
// ignore exception
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::ReferenceError, m_moduleBindings[i].m_localName.string(), false, String::emptyString, ErrorObject::Messages::IsNotInitialized);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -121,12 +121,12 @@ ErrorObject* ErrorObject::createBuiltinError(ExecutionState& state, ErrorCode co
|
|||
|
||||
void ErrorObject::throwBuiltinError(ExecutionState& state, ErrorCode code, String* objectName, bool prototype, String* functionName, const char* templateString)
|
||||
{
|
||||
state.throwException(Value(ErrorObject::createBuiltinError(state, code, objectName, prototype, functionName, templateString)));
|
||||
THROW_EXCEPTION_RETURN(state, Value(ErrorObject::createBuiltinError(state, code, objectName, prototype, functionName, templateString)));
|
||||
}
|
||||
|
||||
void ErrorObject::throwBuiltinError(ExecutionState& state, ErrorCode code, String* errorMessage)
|
||||
{
|
||||
state.throwException(Value(ErrorObject::createError(state, code, errorMessage)));
|
||||
THROW_EXCEPTION_RETURN(state, Value(ErrorObject::createError(state, code, errorMessage)));
|
||||
}
|
||||
|
||||
ErrorObject::ErrorObject(ExecutionState& state, Object* proto, String* errorMessage)
|
||||
|
|
@ -136,6 +136,7 @@ ErrorObject::ErrorObject(ExecutionState& state, Object* proto, String* errorMess
|
|||
if (errorMessage->length()) {
|
||||
defineOwnPropertyThrowsException(state, state.context()->staticStrings().message,
|
||||
ObjectPropertyDescriptor(errorMessage, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectStructurePropertyDescriptor::ConfigurablePresent)));
|
||||
ASSERT(!state.hasPendingException());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,50 @@
|
|||
|
||||
#include "runtime/Object.h"
|
||||
|
||||
#define THROW_BUILTIN_ERROR_RETURN_VALUE(...) \
|
||||
do { \
|
||||
ErrorObject::throwBuiltinError(__VA_ARGS__); \
|
||||
return Value(Value::Exception); \
|
||||
} while (false);
|
||||
|
||||
#define THROW_BUILTIN_ERROR_RETURN_NULL(...) \
|
||||
do { \
|
||||
ErrorObject::throwBuiltinError(__VA_ARGS__); \
|
||||
return nullptr; \
|
||||
} while (false);
|
||||
|
||||
#define THROW_BUILTIN_ERROR_RETURN_ZERO(...) \
|
||||
do { \
|
||||
ErrorObject::throwBuiltinError(__VA_ARGS__); \
|
||||
return 0; \
|
||||
} while (false);
|
||||
|
||||
#define THROW_BUILTIN_ERROR_RETURN(...) \
|
||||
do { \
|
||||
ErrorObject::throwBuiltinError(__VA_ARGS__); \
|
||||
return; \
|
||||
} while (false);
|
||||
|
||||
#define RETURN_VALUE_IF_PENDING_EXCEPTION \
|
||||
if (UNLIKELY(state.hasPendingException())) { \
|
||||
return Value(Value::Exception); \
|
||||
}
|
||||
|
||||
#define RETURN_NULL_IF_PENDING_EXCEPTION \
|
||||
if (UNLIKELY(state.hasPendingException())) { \
|
||||
return nullptr; \
|
||||
}
|
||||
|
||||
#define RETURN_ZERO_IF_PENDING_EXCEPTION \
|
||||
if (UNLIKELY(state.hasPendingException())) { \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
#define RETURN_IF_PENDING_EXCEPTION \
|
||||
if (UNLIKELY(state.hasPendingException())) { \
|
||||
return; \
|
||||
}
|
||||
|
||||
namespace Escargot {
|
||||
|
||||
class ByteCodeBlock;
|
||||
|
|
|
|||
|
|
@ -140,7 +140,7 @@ Value ExecutionPauser::start(ExecutionState& state, ExecutionPauser* self, Objec
|
|||
|
||||
const size_t programStart = reinterpret_cast<size_t>(self->m_byteCodeBlock->m_code.data());
|
||||
Value result;
|
||||
try {
|
||||
{
|
||||
ExecutionState* es;
|
||||
size_t startPos = self->m_byteCodePosition;
|
||||
if (startPos == SIZE_MAX) {
|
||||
|
|
@ -184,6 +184,13 @@ Value ExecutionPauser::start(ExecutionState& state, ExecutionPauser* self, Objec
|
|||
#endif /* ESCARGOT_DEBUGGER */
|
||||
|
||||
result = Interpreter::interpret(es, self->m_byteCodeBlock, startPos, self->m_registerFile);
|
||||
// check exception
|
||||
if (UNLIKELY(result.isException())) {
|
||||
ASSERT(es->hasPendingException());
|
||||
es->unsetPendingException();
|
||||
state.setPendingException();
|
||||
goto IfAbrupt;
|
||||
}
|
||||
|
||||
#ifdef ESCARGOT_DEBUGGER
|
||||
if (activeSavedStackTraceExecutionState != ESCARGOT_DEBUGGER_NO_STACK_TRACE_RESTORE) {
|
||||
|
|
@ -224,36 +231,18 @@ Value ExecutionPauser::start(ExecutionState& state, ExecutionPauser* self, Objec
|
|||
} else if (from == StartFrom::AsyncGenerator) {
|
||||
source->asAsyncGeneratorObject()->m_asyncGeneratorState = AsyncGeneratorObject::Completed;
|
||||
result = AsyncGeneratorObject::asyncGeneratorResolve(state, source->asAsyncGeneratorObject(), result, true);
|
||||
if (UNLIKELY(state.hasPendingException()))
|
||||
goto IfAbrupt;
|
||||
} else {
|
||||
ASSERT(from == StartFrom::Async);
|
||||
Value argv = result;
|
||||
Object::call(state, self->m_promiseCapability.m_resolveFunction, Value(), 1, &argv);
|
||||
if (UNLIKELY(state.hasPendingException()))
|
||||
goto IfAbrupt;
|
||||
result = self->m_promiseCapability.m_promise;
|
||||
}
|
||||
self->release();
|
||||
}
|
||||
} catch (const Value& thrownValue) {
|
||||
auto promiseCapability = self->m_promiseCapability;
|
||||
self->release();
|
||||
if (from == StartFrom::Generator) {
|
||||
ASSERT(from == StartFrom::Generator);
|
||||
source->asGeneratorObject()->m_generatorState = GeneratorObject::GeneratorState::CompletedThrow;
|
||||
throw thrownValue;
|
||||
} else if (from == StartFrom::AsyncGenerator) {
|
||||
if (source->asAsyncGeneratorObject()->m_asyncGeneratorState == AsyncGeneratorObject::SuspendedStart) {
|
||||
throw thrownValue;
|
||||
} else {
|
||||
source->asAsyncGeneratorObject()->m_asyncGeneratorState = AsyncGeneratorObject::Completed;
|
||||
result = AsyncGeneratorObject::asyncGeneratorReject(state, source->asAsyncGeneratorObject(), thrownValue);
|
||||
}
|
||||
} else {
|
||||
// https://www.ecma-international.org/ecma-262/10.0/index.html#sec-async-functions-abstract-operations-async-function-start
|
||||
ASSERT(from == StartFrom::Async);
|
||||
Value argv = thrownValue;
|
||||
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &argv);
|
||||
// Return Completion { [[Type]]: return, [[Value]]: promiseCapability.[[Promise]], [[Target]]: empty }.
|
||||
result = promiseCapability.m_promise;
|
||||
}
|
||||
}
|
||||
|
||||
if (self->m_executionState) {
|
||||
|
|
@ -261,6 +250,33 @@ Value ExecutionPauser::start(ExecutionState& state, ExecutionPauser* self, Objec
|
|||
}
|
||||
|
||||
return result;
|
||||
|
||||
IfAbrupt : {
|
||||
ASSERT(state.hasPendingException());
|
||||
auto promiseCapability = self->m_promiseCapability;
|
||||
self->release();
|
||||
if (from == StartFrom::Generator) {
|
||||
ASSERT(from == StartFrom::Generator);
|
||||
source->asGeneratorObject()->m_generatorState = GeneratorObject::GeneratorState::CompletedThrow;
|
||||
return Value(Value::Exception);
|
||||
} else if (from == StartFrom::AsyncGenerator) {
|
||||
if (source->asAsyncGeneratorObject()->m_asyncGeneratorState == AsyncGeneratorObject::SuspendedStart) {
|
||||
return Value(Value::Exception);
|
||||
} else {
|
||||
Value thrownValue = state.detachPendingException();
|
||||
source->asAsyncGeneratorObject()->m_asyncGeneratorState = AsyncGeneratorObject::Completed;
|
||||
return AsyncGeneratorObject::asyncGeneratorReject(state, source->asAsyncGeneratorObject(), thrownValue);
|
||||
}
|
||||
} else {
|
||||
// https://www.ecma-international.org/ecma-262/10.0/index.html#sec-async-functions-abstract-operations-async-function-start
|
||||
ASSERT(from == StartFrom::Async);
|
||||
Value argv = state.detachPendingException();
|
||||
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &argv);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Return Completion { [[Type]]: return, [[Value]]: promiseCapability.[[Promise]], [[Target]]: empty }.
|
||||
return promiseCapability.m_promise;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ExecutionPauser::pause(ExecutionState& state, Value returnValue, size_t tailDataPosition, size_t tailDataLength, size_t nextProgramCounter, ByteCodeRegisterIndex dstRegisterIndex, ByteCodeRegisterIndex dstStateRegisterIndex, PauseReason reason)
|
||||
|
|
@ -290,6 +306,7 @@ void ExecutionPauser::pause(ExecutionState& state, Value returnValue, size_t tai
|
|||
} else if (isAsyncGenerator) {
|
||||
pauser->asAsyncGeneratorObject()->m_asyncGeneratorState = AsyncGeneratorObject::AsyncGeneratorState::SuspendedYield;
|
||||
returnValue = AsyncGeneratorObject::asyncGeneratorResolve(state, pauser->asAsyncGeneratorObject(), returnValue, false);
|
||||
RETURN_IF_PENDING_EXCEPTION
|
||||
}
|
||||
} else {
|
||||
ASSERT(reason == PauseReason::Await || reason == PauseReason::GeneratorsInitialize);
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ ExecutionState::ExecutionState()
|
|||
, m_lexicalEnvironment(nullptr)
|
||||
, m_stackLimit(0)
|
||||
, m_programCounter(nullptr)
|
||||
, m_parent(0)
|
||||
, m_parent(nullptr)
|
||||
, m_hasRareData(false)
|
||||
, m_inStrictMode(false)
|
||||
, m_isNativeFunctionObjectExecutionContext(false)
|
||||
|
|
@ -41,6 +41,7 @@ ExecutionState::ExecutionState()
|
|||
, m_onTry(false)
|
||||
, m_onCatch(false)
|
||||
, m_onFinally(false)
|
||||
, m_hasPendingException(false)
|
||||
#if defined(ENABLE_TCO)
|
||||
, m_initTCO(false)
|
||||
#endif
|
||||
|
|
@ -62,7 +63,7 @@ ExecutionState::ExecutionState(Context* context)
|
|||
, m_lexicalEnvironment(nullptr)
|
||||
, m_stackLimit(context->vmInstance()->stackLimit())
|
||||
, m_programCounter(nullptr)
|
||||
, m_parent(0)
|
||||
, m_parent(nullptr)
|
||||
, m_hasRareData(false)
|
||||
, m_inStrictMode(false)
|
||||
, m_isNativeFunctionObjectExecutionContext(false)
|
||||
|
|
@ -70,6 +71,7 @@ ExecutionState::ExecutionState(Context* context)
|
|||
, m_onTry(false)
|
||||
, m_onCatch(false)
|
||||
, m_onFinally(false)
|
||||
, m_hasPendingException(false)
|
||||
#if defined(ENABLE_TCO)
|
||||
, m_initTCO(false)
|
||||
#endif
|
||||
|
|
@ -81,9 +83,19 @@ ExecutionState::ExecutionState(Context* context)
|
|||
|
||||
void ExecutionState::throwException(const Value& e)
|
||||
{
|
||||
// should not have unhandled exception
|
||||
ASSERT(!m_hasPendingException);
|
||||
m_hasPendingException = true;
|
||||
context()->throwException(*this, e);
|
||||
}
|
||||
|
||||
Value ExecutionState::detachPendingException()
|
||||
{
|
||||
ASSERT(m_hasPendingException);
|
||||
m_hasPendingException = false;
|
||||
return context()->vmInstance()->currentSandBox()->exception();
|
||||
}
|
||||
|
||||
ExecutionStateRareData* ExecutionState::ensureRareData()
|
||||
{
|
||||
if (!m_hasRareData) {
|
||||
|
|
@ -196,8 +208,7 @@ Object* ExecutionState::findPrivateMemberContextObject()
|
|||
{
|
||||
auto o = mostNearestHomeObject();
|
||||
if (!o) {
|
||||
ErrorObject::throwBuiltinError(*this, ErrorCode::TypeError, "Cannot read/write private member here");
|
||||
return nullptr;
|
||||
THROW_BUILTIN_ERROR_RETURN_NULL(*this, ErrorCode::TypeError, "Cannot read/write private member here");
|
||||
}
|
||||
return convertHomeObjectIntoPrivateMemberContextObject(o.value());
|
||||
}
|
||||
|
|
@ -237,7 +248,9 @@ Value ExecutionState::thisValue()
|
|||
auto fnRecord = envRec->asDeclarativeEnvironmentRecord()->asFunctionEnvironmentRecord();
|
||||
ScriptFunctionObject* f = fnRecord->functionObject();
|
||||
if (f->codeBlock()->isInterpretedCodeBlock() && f->codeBlock()->asInterpretedCodeBlock()->needsToLoadThisBindingFromEnvironment()) {
|
||||
return fnRecord->getThisBinding(*this);
|
||||
Value result = fnRecord->getThisBinding(*this);
|
||||
ASSERT(!this->hasPendingException());
|
||||
return result;
|
||||
} else {
|
||||
return f;
|
||||
}
|
||||
|
|
@ -264,7 +277,7 @@ Value ExecutionState::makeSuperPropertyReference()
|
|||
|
||||
// If env.HasSuperBinding() is false, throw a ReferenceError exception.
|
||||
if (!env->hasSuperBinding()) {
|
||||
ErrorObject::throwBuiltinError(*this, ErrorCode::ReferenceError, ErrorObject::Messages::No_Super_Binding);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(*this, ErrorCode::ReferenceError, ErrorObject::Messages::No_Super_Binding);
|
||||
}
|
||||
|
||||
// Let actualThis be env.GetThisBinding().
|
||||
|
|
@ -297,7 +310,7 @@ Value ExecutionState::getSuperConstructor()
|
|||
|
||||
// If IsConstructor(superConstructor) is false, throw a TypeError exception.
|
||||
if (!superConstructor.isConstructor()) {
|
||||
ErrorObject::throwBuiltinError(*this, ErrorCode::TypeError, ErrorObject::Messages::No_Super_Binding);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(*this, ErrorCode::TypeError, ErrorObject::Messages::No_Super_Binding);
|
||||
}
|
||||
|
||||
// Return superConstructor.
|
||||
|
|
|
|||
|
|
@ -20,6 +20,24 @@
|
|||
#ifndef __EscargotExecutionState__
|
||||
#define __EscargotExecutionState__
|
||||
|
||||
#define THROW_EXCEPTION_RETURN_VALUE(state, e) \
|
||||
do { \
|
||||
state.throwException(e); \
|
||||
return Value(Value::Exception); \
|
||||
} while (false)
|
||||
|
||||
#define THROW_EXCEPTION_RETURN_NULL(state, e) \
|
||||
do { \
|
||||
state.throwException(e); \
|
||||
return nullptr; \
|
||||
} while (false)
|
||||
|
||||
#define THROW_EXCEPTION_RETURN(state, e) \
|
||||
do { \
|
||||
state.throwException(e); \
|
||||
return; \
|
||||
} while (false)
|
||||
|
||||
#include "util/Vector.h"
|
||||
|
||||
namespace Escargot {
|
||||
|
|
@ -81,6 +99,7 @@ public:
|
|||
, m_onTry(false)
|
||||
, m_onCatch(false)
|
||||
, m_onFinally(false)
|
||||
, m_hasPendingException(false)
|
||||
#if defined(ENABLE_TCO)
|
||||
, m_initTCO(false)
|
||||
#endif
|
||||
|
|
@ -94,7 +113,7 @@ public:
|
|||
, m_lexicalEnvironment(nullptr)
|
||||
, m_stackLimit(stackLimit)
|
||||
, m_programCounter(nullptr)
|
||||
, m_parent(0)
|
||||
, m_parent(nullptr)
|
||||
, m_hasRareData(false)
|
||||
, m_inStrictMode(false)
|
||||
, m_isNativeFunctionObjectExecutionContext(false)
|
||||
|
|
@ -102,6 +121,7 @@ public:
|
|||
, m_onTry(false)
|
||||
, m_onCatch(false)
|
||||
, m_onFinally(false)
|
||||
, m_hasPendingException(false)
|
||||
#if defined(ENABLE_TCO)
|
||||
, m_initTCO(false)
|
||||
#endif
|
||||
|
|
@ -123,6 +143,7 @@ public:
|
|||
, m_onTry(false)
|
||||
, m_onCatch(false)
|
||||
, m_onFinally(false)
|
||||
, m_hasPendingException(false)
|
||||
#if defined(ENABLE_TCO)
|
||||
, m_initTCO(false)
|
||||
#endif
|
||||
|
|
@ -144,6 +165,7 @@ public:
|
|||
, m_onTry(false)
|
||||
, m_onCatch(false)
|
||||
, m_onFinally(false)
|
||||
, m_hasPendingException(false)
|
||||
#if defined(ENABLE_TCO)
|
||||
, m_initTCO(false)
|
||||
#endif
|
||||
|
|
@ -168,6 +190,7 @@ public:
|
|||
, m_onTry(false)
|
||||
, m_onCatch(false)
|
||||
, m_onFinally(false)
|
||||
, m_hasPendingException(false)
|
||||
#if defined(ENABLE_TCO)
|
||||
, m_initTCO(false)
|
||||
#endif
|
||||
|
|
@ -268,6 +291,24 @@ public:
|
|||
return m_onFinally;
|
||||
}
|
||||
|
||||
bool hasPendingException() const
|
||||
{
|
||||
return m_hasPendingException;
|
||||
}
|
||||
|
||||
void setPendingException()
|
||||
{
|
||||
ASSERT(!m_hasPendingException);
|
||||
m_hasPendingException = true;
|
||||
}
|
||||
|
||||
void unsetPendingException()
|
||||
{
|
||||
m_hasPendingException = false;
|
||||
}
|
||||
|
||||
Value detachPendingException();
|
||||
|
||||
#if defined(ENABLE_TCO)
|
||||
bool initTCO() const
|
||||
{
|
||||
|
|
@ -361,6 +402,7 @@ private:
|
|||
bool m_onTry : 1;
|
||||
bool m_onCatch : 1;
|
||||
bool m_onFinally : 1;
|
||||
bool m_hasPendingException : 1;
|
||||
#if defined(ENABLE_TCO)
|
||||
bool m_initTCO : 1;
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -178,13 +178,10 @@ void FinalizationRegistryObject::finalizer(Object* self, void* data)
|
|||
}
|
||||
|
||||
if (!wasCallbackDeleted) {
|
||||
try {
|
||||
ExecutionState tempState(item->source->m_realm);
|
||||
Value argv = item->heldValue;
|
||||
Object::call(tempState, item->source->m_cleanupCallback.value(), Value(), 1, &argv);
|
||||
} catch (const Value& v) {
|
||||
// do nothing
|
||||
}
|
||||
ExecutionState tempState(item->source->m_realm);
|
||||
Value argv = item->heldValue;
|
||||
Object::call(tempState, item->source->m_cleanupCallback.value(), Value(), 1, &argv);
|
||||
ASSERT(!tempState.hasPendingException());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -110,6 +110,7 @@ static String* createFunctionSource(ExecutionState& state, AtomicString function
|
|||
|
||||
String* parameterStr = parameters.finalize(&state);
|
||||
String* originBodyStr = bodyValue.toString(state);
|
||||
RETURN_NULL_IF_PENDING_EXCEPTION
|
||||
String* scriptSource = nullptr;
|
||||
|
||||
#if defined(ENABLE_RELOADABLE_STRING)
|
||||
|
|
@ -233,6 +234,9 @@ static String* createFunctionSource(ExecutionState& state, AtomicString function
|
|||
FunctionObject::FunctionSource FunctionObject::createDynamicFunctionScript(ExecutionState& state, AtomicString functionName, size_t argCount, Value* argArray, Value bodyValue, bool useStrict, bool isGenerator, bool isAsync, bool allowSuperCall, bool isInternalSource, String* sourceName)
|
||||
{
|
||||
String* scriptSource = createFunctionSource(state, functionName, argCount, argArray, bodyValue, useStrict, isGenerator, isAsync, isInternalSource);
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
return FunctionObject::FunctionSource();
|
||||
}
|
||||
|
||||
ScriptParser parser(state.context());
|
||||
String* srcName = sourceName;
|
||||
|
|
@ -246,6 +250,9 @@ FunctionObject::FunctionSource FunctionObject::createDynamicFunctionScript(Execu
|
|||
}
|
||||
|
||||
Script* script = parser.initializeScript(nullptr, 0, scriptSource, srcName, nullptr, false, false, false, false, false, allowSuperCall, false, true, false).scriptThrowsExceptionIfParseError(state);
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
return FunctionObject::FunctionSource();
|
||||
}
|
||||
|
||||
InterpretedCodeBlock* cb = script->topCodeBlock()->childBlockAt(0);
|
||||
// mark it as dynamic code
|
||||
|
|
|
|||
|
|
@ -169,6 +169,7 @@ public:
|
|||
return constructorRealm->globalObject()->asyncGeneratorPrototype();
|
||||
});
|
||||
}
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// Return ObjectCreate(proto, internalSlotsList).
|
||||
Object* generatorObject;
|
||||
|
|
@ -181,10 +182,12 @@ public:
|
|||
AsyncGeneratorObject* gen = new AsyncGeneratorObject(state, proto, newState, registerFile, blk);
|
||||
newState->setPauseSource(gen->executionPauser());
|
||||
newState->pauseSource()->m_promiseCapability = PromiseObject::newPromiseCapability(*newState, newState->context()->globalObject()->promise());
|
||||
ASSERT(!newState->hasPendingException());
|
||||
ExecutionPauser::start(state, newState->pauseSource(), newState->pauseSource()->sourceObject(), Value(), false, false, ExecutionPauser::StartFrom::AsyncGenerator);
|
||||
generatorObject = gen;
|
||||
}
|
||||
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
return generatorObject;
|
||||
}
|
||||
|
||||
|
|
@ -195,6 +198,7 @@ public:
|
|||
newState = new ExecutionState(ctx, nullptr, lexEnv, argc, argv, isStrict, ExecutionState::ForPauser);
|
||||
newState->setPauseSource(new ExecutionPauser(state, self, newState, registerFile, blk));
|
||||
newState->pauseSource()->m_promiseCapability = PromiseObject::newPromiseCapability(*newState, newState->context()->globalObject()->promise());
|
||||
ASSERT(!newState->hasPendingException());
|
||||
} else {
|
||||
newState = new (alloca(sizeof(ExecutionState))) ExecutionState(ctx, &state, lexEnv, argc, argv, isStrict);
|
||||
}
|
||||
|
|
@ -204,6 +208,14 @@ public:
|
|||
// https://www.ecma-international.org/ecma-262/6.0/#sec-ordinarycallbindthis
|
||||
// NOTE ToObject produces wrapper objects using calleeRealm. <<----
|
||||
stackStorage[0] = thisValueBinder(state, *newState, self, thisArgument, isStrict);
|
||||
// check thisValueBinder result
|
||||
if (std::is_same<FunctionObjectType, ScriptClassConstructorFunctionObject>::value) {
|
||||
if (UNLIKELY(newState->hasPendingException())) {
|
||||
ASSERT(stackStorage[0].isException());
|
||||
state.setPendingException();
|
||||
return Value(Value::Exception);
|
||||
}
|
||||
}
|
||||
|
||||
if (isConstructCall) {
|
||||
NewTargetBinder newTargetBinder;
|
||||
|
|
@ -217,6 +229,12 @@ public:
|
|||
: Interpreter::interpret(newState, blk, reinterpret_cast<const size_t>(blk->m_code.data()), registerFile),
|
||||
thisArgument, record);
|
||||
|
||||
// check Exception
|
||||
if (UNLIKELY(newState->hasPendingException())) {
|
||||
ASSERT(returnValue.isException());
|
||||
state.setPendingException();
|
||||
}
|
||||
|
||||
if (UNLIKELY(blk->m_shouldClearStack)) {
|
||||
clearStack<512>();
|
||||
}
|
||||
|
|
@ -293,14 +311,21 @@ Value NativeFunctionObject::processNativeFunctionCall(ExecutionState& state, con
|
|||
Value result;
|
||||
if (isConstruct) {
|
||||
result = nativeFunc(newState, receiver, argc, argv, newTarget);
|
||||
if (shouldReturnsObjectOnConstructCall && UNLIKELY(!result.isObject())) {
|
||||
if (shouldReturnsObjectOnConstructCall && UNLIKELY(!result.isObject()) && !newState.hasPendingException()) {
|
||||
// return exception done!
|
||||
ErrorObject::throwBuiltinError(newState, ErrorCode::TypeError, "Native Constructor must returns constructed new object");
|
||||
result = Value(Value::Exception);
|
||||
}
|
||||
} else {
|
||||
ASSERT(!newTarget);
|
||||
result = nativeFunc(newState, receiver, argc, argv, nullptr);
|
||||
}
|
||||
|
||||
// check Exception
|
||||
if (UNLIKELY(newState.hasPendingException())) {
|
||||
ASSERT(result.isException());
|
||||
state.setPendingException();
|
||||
}
|
||||
#ifdef ESCARGOT_DEBUGGER
|
||||
Debugger::updateStopState(state.context()->debugger(), &newState, ESCARGOT_DEBUGGER_ALWAYS_STOP);
|
||||
#endif /* ESCARGOT_DEBUGGER */
|
||||
|
|
|
|||
|
|
@ -53,17 +53,17 @@ void* GeneratorObject::operator new(size_t size)
|
|||
GeneratorObject* GeneratorObject::generatorValidate(ExecutionState& state, const Value& generator)
|
||||
{
|
||||
if (!generator.isObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ThisNotObject);
|
||||
THROW_BUILTIN_ERROR_RETURN_NULL(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ThisNotObject);
|
||||
}
|
||||
|
||||
if (!generator.asObject()->isGeneratorObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().Generator.string(), true, state.context()->staticStrings().next.string(), ErrorObject::Messages::GlobalObject_CalledOnIncompatibleReceiver);
|
||||
THROW_BUILTIN_ERROR_RETURN_NULL(state, ErrorCode::TypeError, state.context()->staticStrings().Generator.string(), true, state.context()->staticStrings().next.string(), ErrorObject::Messages::GlobalObject_CalledOnIncompatibleReceiver);
|
||||
}
|
||||
|
||||
GeneratorObject* gen = generator.asObject()->asGeneratorObject();
|
||||
|
||||
if (gen->generatorState() == GeneratorObject::GeneratorState::Executing) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Generator is already running");
|
||||
THROW_BUILTIN_ERROR_RETURN_NULL(state, ErrorCode::TypeError, "Generator is already running");
|
||||
}
|
||||
|
||||
return gen;
|
||||
|
|
@ -73,6 +73,7 @@ GeneratorObject* GeneratorObject::generatorValidate(ExecutionState& state, const
|
|||
Value GeneratorObject::generatorResume(ExecutionState& state, const Value& generator, const Value& value)
|
||||
{
|
||||
GeneratorObject* gen = generatorValidate(state, generator);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
if (gen->m_generatorState >= GeneratorObject::GeneratorState::CompletedReturn) {
|
||||
return IteratorObject::createIterResultObject(state, Value(), true);
|
||||
|
|
@ -88,6 +89,7 @@ Value GeneratorObject::generatorResume(ExecutionState& state, const Value& gener
|
|||
Value GeneratorObject::generatorResumeAbrupt(ExecutionState& state, const Value& generator, const Value& value, GeneratorObject::GeneratorAbruptType type)
|
||||
{
|
||||
GeneratorObject* gen = generatorValidate(state, generator);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
if (gen->m_generatorState == GeneratorObject::GeneratorState::SuspendedStart) {
|
||||
gen->m_generatorState = GeneratorObject::GeneratorState::CompletedReturn;
|
||||
|
|
@ -97,7 +99,7 @@ Value GeneratorObject::generatorResumeAbrupt(ExecutionState& state, const Value&
|
|||
if (type == GeneratorObject::GeneratorAbruptType::Return) {
|
||||
return IteratorObject::createIterResultObject(state, value, true);
|
||||
}
|
||||
state.throwException(value);
|
||||
THROW_EXCEPTION_RETURN_VALUE(state, value);
|
||||
}
|
||||
|
||||
ASSERT(gen->generatorState() == GeneratorObject::GeneratorState::SuspendedYield);
|
||||
|
|
|
|||
|
|
@ -164,8 +164,7 @@ Value GlobalObject::eval(ExecutionState& state, const Value& arg)
|
|||
Value checkMSG = state.context()->securityPolicyCheckCallback()(state, true);
|
||||
if (!checkMSG.isEmpty()) {
|
||||
ASSERT(checkMSG.isString());
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::EvalError, checkMSG.asString());
|
||||
return Value();
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::EvalError, checkMSG.asString());
|
||||
}
|
||||
}
|
||||
ScriptParser parser(state.context());
|
||||
|
|
@ -180,9 +179,16 @@ Value GlobalObject::eval(ExecutionState& state, const Value& arg)
|
|||
#endif
|
||||
|
||||
Script* script = parser.initializeScript(nullptr, 0, arg.asString(), state.context()->staticStrings().lazyEvalCode().string(), nullptr, false, true, false, false, strictFromOutside, false, false, false, true, stackRemainApprox).scriptThrowsExceptionIfParseError(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// In case of indirect call, use global execution context
|
||||
ExecutionState stateForNewGlobal(m_context);
|
||||
return script->execute(stateForNewGlobal, true, script->topCodeBlock()->isStrict());
|
||||
Value result = script->execute(stateForNewGlobal, true, script->topCodeBlock()->isStrict());
|
||||
// check exception
|
||||
if (UNLIKELY(result.isException())) {
|
||||
ASSERT(stateForNewGlobal.hasPendingException());
|
||||
state.setPendingException();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return arg;
|
||||
}
|
||||
|
|
@ -195,8 +201,7 @@ Value GlobalObject::evalLocal(ExecutionState& state, const Value& arg, Value thi
|
|||
Value checkMSG = state.context()->securityPolicyCheckCallback()(state, true);
|
||||
if (!checkMSG.isEmpty()) {
|
||||
ASSERT(checkMSG.isString());
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::EvalError, checkMSG.asString());
|
||||
return Value();
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::EvalError, checkMSG.asString());
|
||||
}
|
||||
}
|
||||
ScriptParser parser(state.context());
|
||||
|
|
@ -232,6 +237,7 @@ Value GlobalObject::evalLocal(ExecutionState& state, const Value& arg, Value thi
|
|||
false, true, isRunningEvalOnFunction, inWithOperation, strictFromOutside, parentCodeBlock->allowSuperCall(),
|
||||
parentCodeBlock->allowSuperProperty(), allowNewTarget, true, stackRemainApprox)
|
||||
.scriptThrowsExceptionIfParseError(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
return script->executeLocal(state, thisValue, parentCodeBlock, script->topCodeBlock()->isStrict(), isRunningEvalOnFunction);
|
||||
}
|
||||
return arg;
|
||||
|
|
@ -283,6 +289,7 @@ ATTRIBUTE_NO_OPTIMIZE_IF_ARM64_GCC static Value builtinParseInt(ExecutionState&
|
|||
// 1. Let inputString be ToString(string).
|
||||
Value input = argv[0];
|
||||
String* s = input.toString(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// 2. Let S be a newly created substring of inputString consisting of the first character that is not a StrWhiteSpaceChar
|
||||
// and all characters following that character. (In other words, remove leading white space.)
|
||||
|
|
@ -363,6 +370,7 @@ static Value builtinParseFloat(ExecutionState& state, Value thisValue, size_t ar
|
|||
// 1. Let inputString be ToString(string).
|
||||
Value input = argv[0];
|
||||
String* s = input.toString(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
size_t strLen = s->length();
|
||||
|
||||
if (strLen == 1) {
|
||||
|
|
@ -424,6 +432,7 @@ static Value builtinParseFloat(ExecutionState& state, Value thisValue, size_t ar
|
|||
static Value builtinIsFinite(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
double num = argv[0].toNumber(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (std::isnan(num) || num == std::numeric_limits<double>::infinity() || num == -std::numeric_limits<double>::infinity())
|
||||
return Value(Value::False);
|
||||
else
|
||||
|
|
@ -433,6 +442,7 @@ static Value builtinIsFinite(ExecutionState& state, Value thisValue, size_t argc
|
|||
static Value builtinIsNaN(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
double num = argv[0].toNumber(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (std::isnan(num)) {
|
||||
return Value(Value::True);
|
||||
}
|
||||
|
|
@ -490,6 +500,10 @@ inline static bool codeUnitToHexaDecimal(String* str, size_t start, unsigned cha
|
|||
|
||||
static Value decode(ExecutionState& state, String* uriString, bool noComponent, String* funcName)
|
||||
{
|
||||
if (!uriString) {
|
||||
ASSERT(state.hasPendingException());
|
||||
return Value(Value::Exception);
|
||||
}
|
||||
String* globalObjectString = state.context()->staticStrings().GlobalObject.string();
|
||||
StringBuilder unescaped;
|
||||
size_t strLen = uriString->length();
|
||||
|
|
@ -500,15 +514,17 @@ static Value decode(ExecutionState& state, String* uriString, bool noComponent,
|
|||
unescaped.appendChar(t);
|
||||
} else {
|
||||
size_t start = i;
|
||||
if (i + 2 >= strLen)
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::URIError, globalObjectString, false, funcName, ErrorObject::Messages::GlobalObject_MalformedURI);
|
||||
if (i + 2 >= strLen) {
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::URIError, globalObjectString, false, funcName, ErrorObject::Messages::GlobalObject_MalformedURI);
|
||||
}
|
||||
char16_t next = uriString->charAt(i + 1);
|
||||
char16_t nextnext = uriString->charAt(i + 2);
|
||||
|
||||
// char to hex
|
||||
unsigned char b = 0;
|
||||
if (!twocharToHexaDecimal(next, nextnext, &b))
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::URIError, globalObjectString, false, funcName, ErrorObject::Messages::GlobalObject_MalformedURI);
|
||||
if (!twocharToHexaDecimal(next, nextnext, &b)) {
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::URIError, globalObjectString, false, funcName, ErrorObject::Messages::GlobalObject_MalformedURI);
|
||||
}
|
||||
i += 2;
|
||||
|
||||
// most significant bit in b is 0
|
||||
|
|
@ -533,15 +549,16 @@ static Value decode(ExecutionState& state, String* uriString, bool noComponent,
|
|||
n++;
|
||||
}
|
||||
if (n == 1 || n == 5 || (i + (3 * (n - 1)) >= strLen)) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::URIError, globalObjectString, false, funcName, ErrorObject::Messages::GlobalObject_MalformedURI);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::URIError, globalObjectString, false, funcName, ErrorObject::Messages::GlobalObject_MalformedURI);
|
||||
}
|
||||
unsigned char octets[4];
|
||||
octets[0] = b;
|
||||
|
||||
int j = 1;
|
||||
while (j < n) {
|
||||
if (!codeUnitToHexaDecimal(uriString, ++i, &b)) // "%XY" type
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::URIError, globalObjectString, false, funcName, ErrorObject::Messages::GlobalObject_MalformedURI);
|
||||
if (!codeUnitToHexaDecimal(uriString, ++i, &b)) { // "%XY" type
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::URIError, globalObjectString, false, funcName, ErrorObject::Messages::GlobalObject_MalformedURI);
|
||||
}
|
||||
i += 2;
|
||||
octets[j] = b;
|
||||
j++;
|
||||
|
|
@ -551,17 +568,17 @@ static Value decode(ExecutionState& state, String* uriString, bool noComponent,
|
|||
if (n == 2) {
|
||||
v = (octets[0] & 0x1F) << 6 | (octets[1] & 0x3F);
|
||||
if ((octets[0] == 0xC0) || (octets[0] == 0xC1)) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::URIError, globalObjectString, false, funcName, ErrorObject::Messages::GlobalObject_MalformedURI);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::URIError, globalObjectString, false, funcName, ErrorObject::Messages::GlobalObject_MalformedURI);
|
||||
}
|
||||
} else if (n == 3) {
|
||||
v = (octets[0] & 0x0F) << 12 | (octets[1] & 0x3F) << 6 | (octets[2] & 0x3F);
|
||||
if ((0xD800 <= v && v <= 0xDFFF) || ((octets[0] == 0xE0) && ((octets[1] < 0xA0) || (octets[1] > 0xBF)))) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::URIError, globalObjectString, false, funcName, ErrorObject::Messages::GlobalObject_MalformedURI);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::URIError, globalObjectString, false, funcName, ErrorObject::Messages::GlobalObject_MalformedURI);
|
||||
}
|
||||
} else if (n == 4) {
|
||||
v = (octets[0] & 0x07) << 18 | (octets[1] & 0x3F) << 12 | (octets[2] & 0x3F) << 6 | (octets[3] & 0x3F);
|
||||
if ((octets[0] == 0xF0) && ((octets[1] < 0x90) || (octets[1] > 0xBF))) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::URIError, globalObjectString, false, funcName, ErrorObject::Messages::GlobalObject_MalformedURI);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::URIError, globalObjectString, false, funcName, ErrorObject::Messages::GlobalObject_MalformedURI);
|
||||
}
|
||||
}
|
||||
if (v >= 0x10000) {
|
||||
|
|
@ -610,6 +627,10 @@ static inline bool convertAndAppendCodeUnit(URIBuilderString* escaped, char16_t
|
|||
|
||||
static Value encode(ExecutionState& state, String* uriString, bool noComponent, String* funcName)
|
||||
{
|
||||
if (!uriString) {
|
||||
ASSERT(state.hasPendingException());
|
||||
return Value(Value::Exception);
|
||||
}
|
||||
String* globalObjectString = state.context()->staticStrings().GlobalObject.string();
|
||||
auto bad = uriString->bufferAccessData();
|
||||
|
||||
|
|
@ -640,10 +661,10 @@ static Value encode(ExecutionState& state, String* uriString, bool noComponent,
|
|||
convertAndAppendCodeUnit(&escaped, 0x0080 + (index & 0x003F));
|
||||
i++;
|
||||
} else {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::URIError, globalObjectString, false, funcName, ErrorObject::Messages::GlobalObject_MalformedURI);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::URIError, globalObjectString, false, funcName, ErrorObject::Messages::GlobalObject_MalformedURI);
|
||||
}
|
||||
} else if (0xDC00 <= t && t <= 0xDFFF) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::URIError, globalObjectString, false, funcName, ErrorObject::Messages::GlobalObject_MalformedURI);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::URIError, globalObjectString, false, funcName, ErrorObject::Messages::GlobalObject_MalformedURI);
|
||||
} else {
|
||||
RELEASE_ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
|
@ -703,6 +724,7 @@ void char2hex4digit(char16_t dec, URIBuilderString& result)
|
|||
static Value builtinEscape(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
String* str = argv[0].toString(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
auto bad = str->bufferAccessData();
|
||||
size_t length = bad.length;
|
||||
URIBuilderString R;
|
||||
|
|
@ -732,7 +754,7 @@ static Value builtinEscape(ExecutionState& state, Value thisValue, size_t argc,
|
|||
}
|
||||
|
||||
if (UNLIKELY(len > STRING_MAXIMUM_LENGTH)) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, ErrorObject::Messages::String_InvalidStringLength);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::RangeError, ErrorObject::Messages::String_InvalidStringLength);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -764,6 +786,7 @@ char16_t hex2char(char16_t first, char16_t second)
|
|||
static Value builtinUnescape(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
String* str = argv[0].toString(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
size_t length = str->length();
|
||||
UTF16StringDataNonGCStd R;
|
||||
bool unescapeValue = false;
|
||||
|
|
@ -850,7 +873,7 @@ static Value builtinArrayToString(ExecutionState& state, Value thisValue, size_t
|
|||
static Value builtinGenericIteratorNext(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (!thisValue.isObject() || !thisValue.asObject()->isGenericIteratorObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, String::fromASCII("Iterator"), true, state.context()->staticStrings().next.string(), ErrorObject::Messages::GlobalObject_CalledOnIncompatibleReceiver);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, String::fromASCII("Iterator"), true, state.context()->staticStrings().next.string(), ErrorObject::Messages::GlobalObject_CalledOnIncompatibleReceiver);
|
||||
}
|
||||
|
||||
IteratorObject* iter = thisValue.asObject()->asIteratorObject();
|
||||
|
|
@ -934,24 +957,24 @@ void GlobalObject::installOthers(ExecutionState& state)
|
|||
m_asyncIteratorPrototype = new PrototypeObject(state);
|
||||
m_asyncIteratorPrototype->setGlobalIntrinsicObject(state, true);
|
||||
// https://www.ecma-international.org/ecma-262/10.0/index.html#sec-asynciteratorprototype-asynciterator
|
||||
m_asyncIteratorPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(state.context()->vmInstance()->globalSymbols().asyncIterator),
|
||||
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(AtomicString(state, String::fromASCII("[Symbol.asyncIterator]")), builtinSpeciesGetter, 0, NativeFunctionInfo::Strict)),
|
||||
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
|
||||
m_asyncIteratorPrototype->directDefineOwnProperty(state, ObjectPropertyName(state.context()->vmInstance()->globalSymbols().asyncIterator),
|
||||
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(AtomicString(state, String::fromASCII("[Symbol.asyncIterator]")), builtinSpeciesGetter, 0, NativeFunctionInfo::Strict)),
|
||||
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
|
||||
|
||||
m_iteratorPrototype = new PrototypeObject(state);
|
||||
m_iteratorPrototype->setGlobalIntrinsicObject(state, true);
|
||||
// https://www.ecma-international.org/ecma-262/10.0/index.html#sec-%iteratorprototype%-@@iterator
|
||||
m_iteratorPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(state.context()->vmInstance()->globalSymbols().iterator),
|
||||
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(AtomicString(state, String::fromASCII("[Symbol.iterator]")), builtinSpeciesGetter, 0, NativeFunctionInfo::Strict)),
|
||||
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
|
||||
m_iteratorPrototype->directDefineOwnProperty(state, ObjectPropertyName(state.context()->vmInstance()->globalSymbols().iterator),
|
||||
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(AtomicString(state, String::fromASCII("[Symbol.iterator]")), builtinSpeciesGetter, 0, NativeFunctionInfo::Strict)),
|
||||
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
|
||||
|
||||
m_genericIteratorPrototype = new PrototypeObject(state, m_iteratorPrototype);
|
||||
m_genericIteratorPrototype->setGlobalIntrinsicObject(state, true);
|
||||
|
||||
m_genericIteratorPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(state.context()->staticStrings().next),
|
||||
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().next, builtinGenericIteratorNext, 0, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
|
||||
m_genericIteratorPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(state.context()->vmInstance()->globalSymbols().toStringTag),
|
||||
ObjectPropertyDescriptor(Value(String::fromASCII("Iterator")), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::ConfigurablePresent)));
|
||||
m_genericIteratorPrototype->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().next),
|
||||
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().next, builtinGenericIteratorNext, 0, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
|
||||
m_genericIteratorPrototype->directDefineOwnProperty(state, ObjectPropertyName(state.context()->vmInstance()->globalSymbols().toStringTag),
|
||||
ObjectPropertyDescriptor(Value(String::fromASCII("Iterator")), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::ConfigurablePresent)));
|
||||
|
||||
#if defined(ESCARGOT_ENABLE_TEST)
|
||||
AtomicString isFunctionAllocatedOnStackFunctionName(state, "isFunctionAllocatedOnStack");
|
||||
|
|
|
|||
|
|
@ -28,17 +28,18 @@ namespace Escargot {
|
|||
|
||||
class FunctionObject;
|
||||
|
||||
#define RESOLVE_THIS_BINDING_TO_OBJECT(NAME, OBJ, BUILT_IN_METHOD) \
|
||||
if (thisValue.isUndefinedOrNull()) { \
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().OBJ.string(), true, state.context()->staticStrings().BUILT_IN_METHOD.string(), ErrorObject::Messages::GlobalObject_ThisUndefinedOrNull); \
|
||||
} \
|
||||
#define RESOLVE_THIS_BINDING_TO_OBJECT(NAME, OBJ, BUILT_IN_METHOD) \
|
||||
if (thisValue.isUndefinedOrNull()) { \
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().OBJ.string(), true, state.context()->staticStrings().BUILT_IN_METHOD.string(), ErrorObject::Messages::GlobalObject_ThisUndefinedOrNull); \
|
||||
} \
|
||||
Object* NAME = thisValue.toObject(state);
|
||||
|
||||
#define RESOLVE_THIS_BINDING_TO_STRING(NAME, OBJ, BUILT_IN_METHOD) \
|
||||
if (thisValue.isUndefinedOrNull()) { \
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().OBJ.string(), true, state.context()->staticStrings().BUILT_IN_METHOD.string(), ErrorObject::Messages::GlobalObject_ThisUndefinedOrNull); \
|
||||
} \
|
||||
String* NAME = thisValue.toString(state);
|
||||
#define RESOLVE_THIS_BINDING_TO_STRING(NAME, OBJ, BUILT_IN_METHOD) \
|
||||
if (thisValue.isUndefinedOrNull()) { \
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().OBJ.string(), true, state.context()->staticStrings().BUILT_IN_METHOD.string(), ErrorObject::Messages::GlobalObject_ThisUndefinedOrNull); \
|
||||
} \
|
||||
String* NAME = thisValue.toString(state); \
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
|
||||
#define GLOBALOBJECT_BUILTIN_ARRAYBUFFER(F, objName) \
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ IteratorObject::IteratorObject(ExecutionState& state, Object* proto)
|
|||
Value IteratorObject::next(ExecutionState& state)
|
||||
{
|
||||
auto result = advance(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
Object* r = new Object(state);
|
||||
|
||||
r->defineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().value), ObjectPropertyDescriptor(result.first, ObjectPropertyDescriptor::AllPresent));
|
||||
|
|
@ -59,27 +60,32 @@ IteratorRecord* IteratorObject::getIterator(ExecutionState& state, const Value&
|
|||
if (!sync) {
|
||||
// Set method to ? GetMethod(obj, @@asyncIterator).
|
||||
method = Object::getMethod(state, obj, ObjectPropertyName(state.context()->vmInstance()->globalSymbols().asyncIterator));
|
||||
RETURN_NULL_IF_PENDING_EXCEPTION
|
||||
// If method is undefined, then
|
||||
if (method.isUndefined()) {
|
||||
// Let syncMethod be ? GetMethod(obj, @@iterator).
|
||||
auto syncMethod = Object::getMethod(state, obj, ObjectPropertyName(state.context()->vmInstance()->globalSymbols().iterator));
|
||||
RETURN_NULL_IF_PENDING_EXCEPTION
|
||||
// Let syncIteratorRecord be ? GetIterator(obj, sync, syncMethod).
|
||||
auto syncIteratorRecord = getIterator(state, obj, true, syncMethod);
|
||||
RETURN_NULL_IF_PENDING_EXCEPTION
|
||||
// Return ? CreateAsyncFromSyncIterator(syncIteratorRecord).
|
||||
return AsyncFromSyncIteratorObject::createAsyncFromSyncIterator(state, syncIteratorRecord);
|
||||
}
|
||||
} else {
|
||||
// Otherwise, set method to ? GetMethod(obj, @@iterator).
|
||||
method = Object::getMethod(state, obj, ObjectPropertyName(state.context()->vmInstance()->globalSymbols().iterator));
|
||||
RETURN_NULL_IF_PENDING_EXCEPTION
|
||||
}
|
||||
}
|
||||
|
||||
// Let iterator be ? Call(method, obj).
|
||||
Value iterator = Object::call(state, method, obj, 0, nullptr);
|
||||
RETURN_NULL_IF_PENDING_EXCEPTION
|
||||
|
||||
// If Type(iterator) is not Object, throw a TypeError exception.
|
||||
if (!iterator.isObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "result of GetIterator is not an object");
|
||||
THROW_BUILTIN_ERROR_RETURN_NULL(state, ErrorCode::TypeError, "result of GetIterator is not an object");
|
||||
}
|
||||
|
||||
// Let nextMethod be ? GetV(iterator, "next").
|
||||
|
|
@ -105,9 +111,10 @@ Object* IteratorObject::iteratorNext(ExecutionState& state, IteratorRecord* iter
|
|||
Value args[] = { value };
|
||||
result = Object::call(state, nextMethod, iterator, 1, args);
|
||||
}
|
||||
RETURN_NULL_IF_PENDING_EXCEPTION
|
||||
|
||||
if (!result.isObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "result is not an object");
|
||||
THROW_BUILTIN_ERROR_RETURN_NULL(state, ErrorCode::TypeError, "result is not an object");
|
||||
}
|
||||
|
||||
return result.asObject();
|
||||
|
|
@ -117,6 +124,7 @@ Object* IteratorObject::iteratorNext(ExecutionState& state, IteratorRecord* iter
|
|||
bool IteratorObject::iteratorComplete(ExecutionState& state, Object* iterResult)
|
||||
{
|
||||
Value result = iterResult->get(state, ObjectPropertyName(state.context()->staticStrings().done)).value(state, iterResult);
|
||||
RETURN_ZERO_IF_PENDING_EXCEPTION
|
||||
return result.toBoolean(state);
|
||||
}
|
||||
|
||||
|
|
@ -130,6 +138,7 @@ Value IteratorObject::iteratorValue(ExecutionState& state, Object* iterResult)
|
|||
Optional<Object*> IteratorObject::iteratorStep(ExecutionState& state, IteratorRecord* iteratorRecord)
|
||||
{
|
||||
Object* result = IteratorObject::iteratorNext(state, iteratorRecord);
|
||||
RETURN_NULL_IF_PENDING_EXCEPTION
|
||||
bool done = IteratorObject::iteratorComplete(state, result);
|
||||
|
||||
return done ? nullptr : result;
|
||||
|
|
@ -143,33 +152,32 @@ Value IteratorObject::iteratorClose(ExecutionState& state, IteratorRecord* itera
|
|||
IteratorRecord* record = iteratorRecord;
|
||||
Value iterator = record->m_iterator;
|
||||
Value returnFunction = Object::getMethod(state, iterator, ObjectPropertyName(strings->stringReturn));
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (returnFunction.isUndefined()) {
|
||||
if (hasThrowOnCompletionType) {
|
||||
state.throwException(completionValue);
|
||||
THROW_EXCEPTION_RETURN_VALUE(state, completionValue);
|
||||
}
|
||||
return completionValue;
|
||||
}
|
||||
|
||||
// Let innerResult be Call(return, iterator, « »).
|
||||
Value innerResult;
|
||||
bool innerResultHasException = false;
|
||||
try {
|
||||
innerResult = Object::call(state, returnFunction, iterator, 0, nullptr);
|
||||
} catch (const Value& e) {
|
||||
innerResult = e;
|
||||
Value innerResult = Object::call(state, returnFunction, iterator, 0, nullptr);
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
innerResult = state.detachPendingException();
|
||||
innerResultHasException = true;
|
||||
}
|
||||
// If completion.[[type]] is throw, return Completion(completion).
|
||||
if (hasThrowOnCompletionType) {
|
||||
state.throwException(completionValue);
|
||||
THROW_EXCEPTION_RETURN_VALUE(state, completionValue);
|
||||
}
|
||||
// If innerResult.[[type]] is throw, return Completion(innerResult).
|
||||
if (innerResultHasException) {
|
||||
state.throwException(innerResult);
|
||||
THROW_EXCEPTION_RETURN_VALUE(state, innerResult);
|
||||
}
|
||||
// If Type(innerResult.[[value]]) is not Object, throw a TypeError exception.
|
||||
if (!innerResult.isObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Iterator close result is not an object");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Iterator close result is not an object");
|
||||
}
|
||||
// Return Completion(completion).
|
||||
return completionValue;
|
||||
|
|
@ -196,8 +204,15 @@ ValueVectorWithInlineStorage IteratorObject::iterableToList(ExecutionState& stat
|
|||
ValueVectorWithInlineStorage values;
|
||||
Optional<Object*> next;
|
||||
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
return values;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
next = IteratorObject::iteratorStep(state, iteratorRecord);
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
return values;
|
||||
}
|
||||
if (next.hasValue()) {
|
||||
Value nextValue = IteratorObject::iteratorValue(state, next.value());
|
||||
values.pushBack(nextValue);
|
||||
|
|
@ -215,9 +230,12 @@ ValueVector IteratorObject::iterableToListOfType(ExecutionState& state, const Va
|
|||
IteratorRecord* iteratorRecord = IteratorObject::getIterator(state, items, true);
|
||||
ValueVector values;
|
||||
Optional<Object*> next;
|
||||
// ignore exception
|
||||
ASSERT(!state.hasPendingException());
|
||||
|
||||
while (true) {
|
||||
next = IteratorObject::iteratorStep(state, iteratorRecord);
|
||||
ASSERT(!state.hasPendingException());
|
||||
if (!next.hasValue()) {
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -123,6 +123,7 @@ static Value parseJSONWorker(ExecutionState& state, rapidjson::GenericValue<JSON
|
|||
ArrayObject* arr = new ArrayObject(state, value.Size(), false);
|
||||
for (size_t i = 0; i < value.Size(); i++) {
|
||||
arr->defineOwnIndexedPropertyWithoutExpanding(state, i, parseJSONWorker<CharType, JSONCharType>(state, value[i]));
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
}
|
||||
return arr;
|
||||
} else if (value.IsObject()) {
|
||||
|
|
@ -133,9 +134,12 @@ static Value parseJSONWorker(ExecutionState& state, rapidjson::GenericValue<JSON
|
|||
auto iter = value.MemberBegin();
|
||||
while (iter != value.MemberEnd()) {
|
||||
Value propertyName = parseJSONWorker<CharType, JSONCharType>(state, iter->name);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
ASSERT(propertyName.isString());
|
||||
Value val = parseJSONWorker<CharType, JSONCharType>(state, iter->value);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
obj->defineOwnProperty(state, ObjectPropertyName(AtomicString(state, propertyName.toString(state))),
|
||||
ObjectPropertyDescriptor(parseJSONWorker<CharType, JSONCharType>(state, iter->value), ObjectPropertyDescriptor::AllPresent));
|
||||
ObjectPropertyDescriptor(val, ObjectPropertyDescriptor::AllPresent));
|
||||
iter++;
|
||||
}
|
||||
return obj;
|
||||
|
|
@ -153,7 +157,7 @@ static Value parseJSON(ExecutionState& state, const CharType* data, size_t lengt
|
|||
JSONStringStream<JSONCharType> stringStream(data, length);
|
||||
jsonDocument.ParseStream(stringStream);
|
||||
if (jsonDocument.HasParseError()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::SyntaxError, strings->JSON.string(), true, strings->parse.string(), rapidjson::GetParseError_En(jsonDocument.GetParseError()));
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::SyntaxError, strings->JSON.string(), true, strings->parse.string(), rapidjson::GetParseError_En(jsonDocument.GetParseError()));
|
||||
}
|
||||
|
||||
return parseJSONWorker<CharType, JSONCharType>(state, jsonDocument);
|
||||
|
|
@ -188,6 +192,7 @@ Value JSON::parse(ExecutionState& state, Value text, Value reviver)
|
|||
|
||||
// 1, 2, 3
|
||||
String* JText = text.toString(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
Value unfiltered;
|
||||
|
||||
if (JText->has8BitContent()) {
|
||||
|
|
@ -202,6 +207,7 @@ Value JSON::parse(ExecutionState& state, Value text, Value reviver)
|
|||
} else {
|
||||
unfiltered = parseJSON<char16_t, rapidjson::UTF16<char16_t>>(state, JText->characters16(), JText->length());
|
||||
}
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// 4
|
||||
if (reviver.isCallable()) {
|
||||
|
|
@ -212,12 +218,16 @@ Value JSON::parse(ExecutionState& state, Value text, Value reviver)
|
|||
Walk = [&](Value holder, const ObjectPropertyName& name) -> Value {
|
||||
Value val = holder.asPointerValue()->asObject()->get(state, name).value(state, holder);
|
||||
if (val.isObject()) {
|
||||
if (val.asObject()->isArray(state)) {
|
||||
bool isArray = val.asObject()->isArray(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (isArray) {
|
||||
Object* object = val.asObject();
|
||||
uint32_t i = 0;
|
||||
uint32_t len = object->length(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
while (i < len) {
|
||||
Value newElement = Walk(val, ObjectPropertyName(state, Value(i).toString(state)));
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (newElement.isUndefined()) {
|
||||
object->deleteOwnProperty(state, ObjectPropertyName(state, Value(i).toString(state)));
|
||||
} else {
|
||||
|
|
@ -231,6 +241,7 @@ Value JSON::parse(ExecutionState& state, Value text, Value reviver)
|
|||
uint32_t len = arrObject->arrayLength();
|
||||
while (i < len) {
|
||||
Value newElement = Walk(val, ObjectPropertyName(state, Value(i).toString(state)));
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (newElement.isUndefined()) {
|
||||
arrObject->deleteOwnProperty(state, ObjectPropertyName(state, Value(i).toString(state)));
|
||||
} else {
|
||||
|
|
@ -261,6 +272,7 @@ Value JSON::parse(ExecutionState& state, Value text, Value reviver)
|
|||
|
||||
for (auto& key : keys) {
|
||||
Value newElement = Walk(val, key);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (newElement.isUndefined()) {
|
||||
object->deleteOwnProperty(state, key);
|
||||
} else {
|
||||
|
|
@ -326,20 +338,26 @@ static bool builtinJSONStringifyStr(ExecutionState& state, Value key, Object* ho
|
|||
Value toJson = Object::getV(state, value, ObjectPropertyName(state, strings->toJSON));
|
||||
if (toJson.isCallable()) {
|
||||
Value arguments[] = { key.toString(state) };
|
||||
RETURN_ZERO_IF_PENDING_EXCEPTION
|
||||
value = Object::call(state, toJson, value, 1, arguments);
|
||||
RETURN_ZERO_IF_PENDING_EXCEPTION
|
||||
}
|
||||
}
|
||||
|
||||
if (!replacerFunc.isUndefined()) {
|
||||
Value arguments[] = { key.toString(state), value };
|
||||
RETURN_ZERO_IF_PENDING_EXCEPTION
|
||||
value = Object::call(state, replacerFunc, holder, 2, arguments);
|
||||
RETURN_ZERO_IF_PENDING_EXCEPTION
|
||||
}
|
||||
|
||||
if (value.isObject()) {
|
||||
if (value.asObject()->isNumberObject()) {
|
||||
value = Value(Value::DoubleToIntConvertibleTestNeeds, value.toNumber(state));
|
||||
RETURN_ZERO_IF_PENDING_EXCEPTION
|
||||
} else if (value.asObject()->isStringObject()) {
|
||||
value = Value(value.toString(state));
|
||||
RETURN_ZERO_IF_PENDING_EXCEPTION
|
||||
} else if (value.asObject()->isBooleanObject()) {
|
||||
value = Value(value.asObject()->asBooleanObject()->primitiveValue());
|
||||
} else if (value.asObject()->isBigIntObject()) {
|
||||
|
|
@ -360,6 +378,7 @@ static bool builtinJSONStringifyStr(ExecutionState& state, Value key, Object* ho
|
|||
}
|
||||
if (value.isNumber()) {
|
||||
double d = value.toNumber(state);
|
||||
RETURN_ZERO_IF_PENDING_EXCEPTION
|
||||
if (std::isfinite(d)) {
|
||||
product.appendString(value.toString(state));
|
||||
return true;
|
||||
|
|
@ -368,12 +387,15 @@ static bool builtinJSONStringifyStr(ExecutionState& state, Value key, Object* ho
|
|||
return true;
|
||||
}
|
||||
if (value.isBigInt()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Could not serialize a BigInt");
|
||||
THROW_BUILTIN_ERROR_RETURN_ZERO(state, ErrorCode::TypeError, "Could not serialize a BigInt");
|
||||
}
|
||||
if (value.isObject() && !value.isCallable()) {
|
||||
if (value.asObject()->isArray(state)) {
|
||||
bool isArray = value.asObject()->isArray(state);
|
||||
RETURN_ZERO_IF_PENDING_EXCEPTION
|
||||
if (isArray) {
|
||||
builtinJSONStringifyJA(state, value.asObject(), strings, replacerFunc, stack, indent, gap, propertyListTouched, propertyList, product);
|
||||
} else {
|
||||
RETURN_ZERO_IF_PENDING_EXCEPTION
|
||||
builtinJSONStringifyJO(state, value.asObject(), strings, replacerFunc, stack, indent, gap, propertyListTouched, propertyList, product);
|
||||
}
|
||||
return true;
|
||||
|
|
@ -392,7 +414,7 @@ static void builtinJSONStringifyJA(ExecutionState& state, Object* obj,
|
|||
for (size_t i = 0; i < stack.size(); i++) {
|
||||
Value& v = stack[i];
|
||||
if (v == Value(obj)) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->JSON.string(), false, strings->stringify.string(), ErrorObject::Messages::GlobalObject_JAError);
|
||||
THROW_BUILTIN_ERROR_RETURN(state, ErrorCode::TypeError, strings->JSON.string(), false, strings->stringify.string(), ErrorObject::Messages::GlobalObject_JAError);
|
||||
}
|
||||
}
|
||||
// 2
|
||||
|
|
@ -407,10 +429,11 @@ static void builtinJSONStringifyJA(ExecutionState& state, Object* obj,
|
|||
|
||||
// 6, 7
|
||||
uint32_t len = obj->length(state);
|
||||
RETURN_IF_PENDING_EXCEPTION
|
||||
|
||||
// Each array element requires at least 1 character for the value, and 1 character for the separator
|
||||
if (len / 2 > STRING_MAXIMUM_LENGTH) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, strings->JSON.string(), false, strings->stringify.string(), ErrorObject::Messages::GlobalObject_JAError);
|
||||
THROW_BUILTIN_ERROR_RETURN(state, ErrorCode::RangeError, strings->JSON.string(), false, strings->stringify.string(), ErrorObject::Messages::GlobalObject_JAError);
|
||||
}
|
||||
|
||||
// 8 ~ 9
|
||||
|
|
@ -436,6 +459,7 @@ static void builtinJSONStringifyJA(ExecutionState& state, Object* obj,
|
|||
}
|
||||
|
||||
bool strP = builtinJSONStringifyStr(state, Value(index), obj, strings, replacerFunc, stack, indent, gap, propertyListTouched, propertyList, product);
|
||||
RETURN_IF_PENDING_EXCEPTION
|
||||
if (!strP) {
|
||||
product.appendString(strings->null.string());
|
||||
}
|
||||
|
|
@ -463,7 +487,7 @@ static void builtinJSONStringifyJO(ExecutionState& state, Object* value,
|
|||
// 1
|
||||
for (size_t i = 0; i < stack.size(); i++) {
|
||||
if (stack[i] == value) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->JSON.string(), false, strings->stringify.string(), ErrorObject::Messages::GlobalObject_JOError);
|
||||
THROW_BUILTIN_ERROR_RETURN(state, ErrorCode::TypeError, strings->JSON.string(), false, strings->stringify.string(), ErrorObject::Messages::GlobalObject_JOError);
|
||||
}
|
||||
}
|
||||
// 2
|
||||
|
|
@ -492,6 +516,7 @@ static void builtinJSONStringifyJO(ExecutionState& state, Object* value,
|
|||
LargeStringBuilder subProduct;
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
auto strP = builtinJSONStringifyStr(state, k[i], value, strings, replacerFunc, stack, indent, gap, propertyListTouched, propertyList, subProduct);
|
||||
RETURN_IF_PENDING_EXCEPTION
|
||||
if (strP) {
|
||||
if (first) {
|
||||
if (gap->length()) {
|
||||
|
|
@ -509,6 +534,7 @@ static void builtinJSONStringifyJO(ExecutionState& state, Object* value,
|
|||
}
|
||||
|
||||
builtinJSONStringifyQuote(state, k[i], product);
|
||||
RETURN_IF_PENDING_EXCEPTION
|
||||
product.appendChar(':');
|
||||
if (gap->length() != 0) {
|
||||
product.appendChar(' ');
|
||||
|
|
@ -606,6 +632,7 @@ static void builtinJSONStringifyQuote(ExecutionState& state, String* value, Larg
|
|||
static void builtinJSONStringifyQuote(ExecutionState& state, Value value, LargeStringBuilder& product)
|
||||
{
|
||||
String* str = value.toString(state);
|
||||
RETURN_IF_PENDING_EXCEPTION
|
||||
builtinJSONStringifyQuote(state, str, product);
|
||||
}
|
||||
|
||||
|
|
@ -643,26 +670,34 @@ Value JSON::stringify(ExecutionState& state, Value value, Value replacer, Value
|
|||
Value property = arrObject->get(state, ObjectPropertyName(state, Value(indexes[i]))).value(state, arrObject);
|
||||
builtinJSONArrayReplacerHelper(state, propertyList, property);
|
||||
}
|
||||
} else if (replacer.asObject()->isArray(state)) {
|
||||
propertyListTouched = true;
|
||||
Object* replacerObj = replacer.asObject();
|
||||
uint64_t len = replacerObj->length(state);
|
||||
uint64_t k = 0;
|
||||
} else {
|
||||
bool isArray = replacer.asObject()->isArray(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (isArray) {
|
||||
propertyListTouched = true;
|
||||
Object* replacerObj = replacer.asObject();
|
||||
uint64_t len = replacerObj->length(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
uint64_t k = 0;
|
||||
|
||||
while (k < len) {
|
||||
Value v = replacerObj->getIndexedProperty(state, Value(k)).value(state, replacerObj);
|
||||
builtinJSONArrayReplacerHelper(state, propertyList, v);
|
||||
k++;
|
||||
while (k < len) {
|
||||
Value v = replacerObj->getIndexedProperty(state, Value(k)).value(state, replacerObj);
|
||||
builtinJSONArrayReplacerHelper(state, propertyList, v);
|
||||
k++;
|
||||
}
|
||||
}
|
||||
}
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
}
|
||||
|
||||
// 5
|
||||
if (space.isObject()) {
|
||||
if (space.isPointerValue() && space.asPointerValue()->isNumberObject()) {
|
||||
space = Value(Value::DoubleToIntConvertibleTestNeeds, space.toNumber(state));
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
} else if (space.isPointerValue() && space.asPointerValue()->isStringObject()) {
|
||||
space = space.toString(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -692,6 +727,7 @@ Value JSON::stringify(ExecutionState& state, Value value, Value replacer, Value
|
|||
wrapper->defineOwnProperty(state, ObjectPropertyName(state, String::emptyString), ObjectPropertyDescriptor(value, ObjectPropertyDescriptor::AllPresent));
|
||||
LargeStringBuilder product;
|
||||
auto ret = builtinJSONStringifyStr(state, String::emptyString, wrapper, strings, replacerFunc, stack, indent, gap, propertyListTouched, propertyList, product);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (ret) {
|
||||
return product.finalize(&state);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,26 +64,31 @@ SandBox::SandBoxResult PromiseReactionJob::run()
|
|||
return Object::call(state, m_reaction.m_capability.m_rejectFunction, Value(), 1, value);
|
||||
}
|
||||
|
||||
Value res;
|
||||
try {
|
||||
Value argument = m_argument;
|
||||
res = Object::call(state, m_reaction.m_handler, Value(), 1, &argument);
|
||||
// m_reaction.m_capability can be null when there was no result capability when promise.then()
|
||||
if (m_reaction.m_capability.m_promise != nullptr) {
|
||||
Value value[] = { res };
|
||||
Object::call(state, m_reaction.m_capability.m_resolveFunction, Value(), 1, value);
|
||||
}
|
||||
} catch (const Value& v) {
|
||||
Value reason = v;
|
||||
if (m_reaction.m_capability.m_rejectFunction) {
|
||||
return Object::call(state, m_reaction.m_capability.m_rejectFunction, Value(), 1, &reason);
|
||||
} else {
|
||||
state.throwException(reason);
|
||||
}
|
||||
}
|
||||
Value argument = m_argument;
|
||||
Value res = Object::call(state, m_reaction.m_handler, Value(), 1, &argument);
|
||||
if (UNLIKELY(state.hasPendingException()))
|
||||
goto IfAbrupt;
|
||||
|
||||
// m_reaction.m_capability can be null when there was no result capability when promise.then()
|
||||
if (m_reaction.m_capability.m_promise != nullptr) {
|
||||
Value value[] = { res };
|
||||
Object::call(state, m_reaction.m_capability.m_resolveFunction, Value(), 1, value);
|
||||
if (UNLIKELY(state.hasPendingException()))
|
||||
goto IfAbrupt;
|
||||
}
|
||||
return res;
|
||||
});
|
||||
|
||||
IfAbrupt : {
|
||||
ASSERT(state.hasPendingException());
|
||||
Value reason = state.detachPendingException();
|
||||
if (m_reaction.m_capability.m_rejectFunction) {
|
||||
return Object::call(state, m_reaction.m_capability.m_rejectFunction, Value(), 1, &reason);
|
||||
} else {
|
||||
THROW_EXCEPTION_RETURN_VALUE(state, reason);
|
||||
}
|
||||
}
|
||||
},
|
||||
state);
|
||||
|
||||
#ifdef ESCARGOT_DEBUGGER
|
||||
if (activeSavedStackTraceExecutionState != ESCARGOT_DEBUGGER_NO_STACK_TRACE_RESTORE) {
|
||||
|
|
@ -108,18 +113,15 @@ SandBox::SandBoxResult PromiseResolveThenableJob::run()
|
|||
return sandbox.run([&]() -> Value {
|
||||
auto strings = &state.context()->staticStrings();
|
||||
PromiseReaction::Capability capability = m_promise->createResolvingFunctions(state);
|
||||
|
||||
Value result;
|
||||
try {
|
||||
Value arguments[] = { capability.m_resolveFunction, capability.m_rejectFunction };
|
||||
result = Object::call(state, m_then, m_thenable, 2, arguments);
|
||||
} catch (const Value& v) {
|
||||
Value reason = v;
|
||||
Value arguments[] = { capability.m_resolveFunction, capability.m_rejectFunction };
|
||||
Value result = Object::call(state, m_then, m_thenable, 2, arguments);
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
Value reason = state.detachPendingException();
|
||||
return Object::call(state, capability.m_rejectFunction, Value(), 1, &reason);
|
||||
}
|
||||
|
||||
return result;
|
||||
});
|
||||
},
|
||||
state);
|
||||
}
|
||||
|
||||
SandBox::SandBoxResult CleanupSomeJob::run()
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ ObjectStructurePropertyName::ObjectStructurePropertyName(const Value& value)
|
|||
ObjectStructurePropertyName::ObjectStructurePropertyName(ExecutionState& state, const Value& valueIn)
|
||||
{
|
||||
Value value = valueIn.toPrimitive(state, Value::PreferString);
|
||||
RETURN_IF_PENDING_EXCEPTION
|
||||
if (UNLIKELY(value.isSymbol())) {
|
||||
m_data = (size_t)value.asSymbol();
|
||||
return;
|
||||
|
|
@ -217,8 +218,11 @@ ObjectPropertyDescriptor::ObjectPropertyDescriptor(ExecutionState& state, Object
|
|||
m_property = NotPresent;
|
||||
const StaticStrings* strings = &state.context()->staticStrings();
|
||||
auto desc = obj->get(state, ObjectPropertyName(strings->enumerable));
|
||||
if (desc.hasValue())
|
||||
setEnumerable(desc.value(state, obj).toBoolean(state));
|
||||
if (desc.hasValue()) {
|
||||
Value val = desc.value(state, obj);
|
||||
RETURN_IF_PENDING_EXCEPTION
|
||||
setEnumerable(val.toBoolean(state));
|
||||
}
|
||||
desc = obj->get(state, ObjectPropertyName(strings->configurable));
|
||||
if (desc.hasValue())
|
||||
setConfigurable(desc.value(state, obj).toBoolean(state));
|
||||
|
|
@ -241,7 +245,7 @@ ObjectPropertyDescriptor::ObjectPropertyDescriptor(ExecutionState& state, Object
|
|||
if (desc.hasValue()) {
|
||||
Value getter = desc.value(state, obj);
|
||||
if (!getter.isCallable() && !getter.isUndefined()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Getter must be a function or undefined");
|
||||
THROW_BUILTIN_ERROR_RETURN(state, ErrorCode::TypeError, "Getter must be a function or undefined");
|
||||
} else {
|
||||
m_isDataProperty = false;
|
||||
m_getterSetter = JSGetterSetter(getter, Value(Value::EmptyValue));
|
||||
|
|
@ -252,7 +256,7 @@ ObjectPropertyDescriptor::ObjectPropertyDescriptor(ExecutionState& state, Object
|
|||
if (desc.hasValue()) {
|
||||
Value setter = desc.value(state, obj);
|
||||
if (!setter.isCallable() && !setter.isUndefined()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Setter must be a function or undefined");
|
||||
THROW_BUILTIN_ERROR_RETURN(state, ErrorCode::TypeError, "Setter must be a function or undefined");
|
||||
} else {
|
||||
if (m_isDataProperty) {
|
||||
m_isDataProperty = false;
|
||||
|
|
@ -264,7 +268,7 @@ ObjectPropertyDescriptor::ObjectPropertyDescriptor(ExecutionState& state, Object
|
|||
}
|
||||
|
||||
if (!m_isDataProperty && (hasWritable || hasValue)) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Invalid property descriptor. Cannot both specify accessors and a value or writable attribute");
|
||||
THROW_BUILTIN_ERROR_RETURN(state, ErrorCode::TypeError, "Invalid property descriptor. Cannot both specify accessors and a value or writable attribute");
|
||||
}
|
||||
|
||||
ASSERT(checkProperty());
|
||||
|
|
@ -520,6 +524,7 @@ bool Object::isConcatSpreadable(ExecutionState& state)
|
|||
}
|
||||
// Let spreadable be Get(O, @@isConcatSpreadable).
|
||||
Value spreadable = get(state, ObjectPropertyName(state.context()->vmInstance()->globalSymbols().isConcatSpreadable)).value(state, this);
|
||||
RETURN_ZERO_IF_PENDING_EXCEPTION
|
||||
// If spreadable is not undefined, return ToBoolean(spreadable).
|
||||
if (!spreadable.isUndefined()) {
|
||||
return spreadable.toBoolean(state);
|
||||
|
|
@ -1215,6 +1220,7 @@ static Object* internalFastToObjectForGetMethodGetV(ExecutionState& state, const
|
|||
Value Object::getMethod(ExecutionState& state, const Value& O, const ObjectPropertyName& propertyName)
|
||||
{
|
||||
Object* obj = internalFastToObjectForGetMethodGetV(state, O);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
auto r = obj->getMethod(state, propertyName);
|
||||
if (r) {
|
||||
return Value(r.value());
|
||||
|
|
@ -1226,13 +1232,14 @@ Optional<Object*> Object::getMethod(ExecutionState& state, const ObjectPropertyN
|
|||
{
|
||||
// 2. Let func be GetV(O, P).
|
||||
Value func = get(state, propertyName).value(state, this);
|
||||
RETURN_NULL_IF_PENDING_EXCEPTION
|
||||
// 4. If func is either undefined or null, return undefined.
|
||||
if (func.isUndefinedOrNull()) {
|
||||
return nullptr;
|
||||
}
|
||||
// 5. If IsCallable(func) is false, throw a TypeError exception.
|
||||
if (!func.isCallable()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, String::emptyString, false, String::emptyString, "%s: return value of getMethod is not callable");
|
||||
THROW_BUILTIN_ERROR_RETURN_NULL(state, ErrorCode::TypeError, String::emptyString, false, String::emptyString, "%s: return value of getMethod is not callable");
|
||||
}
|
||||
// 6. Return func.
|
||||
return Optional<Object*>(func.asObject());
|
||||
|
|
@ -1256,13 +1263,17 @@ Object* Object::getPrototypeFromConstructor(ExecutionState& state, Object* const
|
|||
} else {
|
||||
// Let proto be ? Get(constructor, "prototype").
|
||||
proto = constructor->get(state, ObjectPropertyName(state.context()->staticStrings().prototype)).value(state, constructor);
|
||||
RETURN_NULL_IF_PENDING_EXCEPTION
|
||||
}
|
||||
|
||||
// If Type(proto) is not Object, then
|
||||
if (!proto.isObject()) {
|
||||
// Let realm be ? GetFunctionRealm(constructor).
|
||||
// Set proto to realm's intrinsic object named intrinsicDefaultProto.
|
||||
proto = intrinsicDefaultProtoGetter(state, constructor->getFunctionRealm(state));
|
||||
Context* c = constructor->getFunctionRealm(state);
|
||||
RETURN_NULL_IF_PENDING_EXCEPTION
|
||||
proto = intrinsicDefaultProtoGetter(state, c);
|
||||
RETURN_NULL_IF_PENDING_EXCEPTION
|
||||
} else {
|
||||
proto.asObject()->markAsPrototypeObject(state);
|
||||
}
|
||||
|
|
@ -1274,7 +1285,7 @@ Object* Object::getPrototypeFromConstructor(ExecutionState& state, Object* const
|
|||
Value Object::call(ExecutionState& state, const Value& callee, const Value& thisValue, const size_t argc, Value* argv)
|
||||
{
|
||||
if (!callee.isPointerValue()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::NOT_Callable);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::NOT_Callable);
|
||||
}
|
||||
// Return F.[[Call]](V, argumentsList).
|
||||
return callee.asPointerValue()->call(state, thisValue, argc, argv);
|
||||
|
|
@ -1299,6 +1310,7 @@ bool Object::setIntegrityLevel(ExecutionState& state, Object* O, bool isSealed)
|
|||
{
|
||||
// Let status be ? O.[[PreventExtensions]]().
|
||||
bool status = O->preventExtensions(state);
|
||||
RETURN_ZERO_IF_PENDING_EXCEPTION
|
||||
// If status is false, return false.
|
||||
if (!status) {
|
||||
return false;
|
||||
|
|
@ -1318,6 +1330,7 @@ bool Object::setIntegrityLevel(ExecutionState& state, Object* O, bool isSealed)
|
|||
newDesc.setConfigurable(false);
|
||||
|
||||
O->defineOwnPropertyThrowsException(state, ObjectPropertyName(state, keys[i]), newDesc);
|
||||
RETURN_ZERO_IF_PENDING_EXCEPTION
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
@ -1337,6 +1350,7 @@ bool Object::setIntegrityLevel(ExecutionState& state, Object* O, bool isSealed)
|
|||
}
|
||||
// Perform ? DefinePropertyOrThrow(O, k, desc).
|
||||
O->defineOwnPropertyThrowsException(state, ObjectPropertyName(state, keys[i]), newDesc);
|
||||
RETURN_ZERO_IF_PENDING_EXCEPTION
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1401,12 +1415,14 @@ bool Object::hasInstance(ExecutionState& state, Value O)
|
|||
}
|
||||
// Let P be Get(C, "prototype").
|
||||
Value P = C->get(state, state.context()->staticStrings().prototype).value(state, C);
|
||||
RETURN_ZERO_IF_PENDING_EXCEPTION
|
||||
// If Type(P) is not Object, throw a TypeError exception.
|
||||
if (!P.isObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::InstanceOf_InvalidPrototypeProperty);
|
||||
THROW_BUILTIN_ERROR_RETURN_ZERO(state, ErrorCode::TypeError, ErrorObject::Messages::InstanceOf_InvalidPrototypeProperty);
|
||||
}
|
||||
// Repeat
|
||||
O = O.asObject()->getPrototype(state);
|
||||
RETURN_ZERO_IF_PENDING_EXCEPTION
|
||||
while (!O.isNull()) {
|
||||
// If O is null, return false.
|
||||
// If SameValue(P, O) is true, return true.
|
||||
|
|
@ -1415,6 +1431,7 @@ bool Object::hasInstance(ExecutionState& state, Value O)
|
|||
}
|
||||
// Let O be O.[[GetPrototypeOf]]().
|
||||
O = O.asObject()->getPrototype(state);
|
||||
RETURN_ZERO_IF_PENDING_EXCEPTION
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1499,30 +1516,32 @@ bool Object::isCompatiblePropertyDescriptor(ExecutionState& state, bool extensib
|
|||
void Object::setThrowsException(ExecutionState& state, const ObjectPropertyName& P, const Value& v, const Value& receiver)
|
||||
{
|
||||
if (UNLIKELY(!set(state, P, v, receiver))) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, P.toExceptionString(), false, String::emptyString, ErrorObject::Messages::DefineProperty_NotWritable);
|
||||
RETURN_IF_PENDING_EXCEPTION
|
||||
THROW_BUILTIN_ERROR_RETURN(state, ErrorCode::TypeError, P.toExceptionString(), false, String::emptyString, ErrorObject::Messages::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, ErrorCode::TypeError, P.toExceptionString(), false, String::emptyString, ErrorObject::Messages::DefineProperty_NotWritable);
|
||||
RETURN_IF_PENDING_EXCEPTION
|
||||
THROW_BUILTIN_ERROR_RETURN(state, ErrorCode::TypeError, P.toExceptionString(), false, String::emptyString, ErrorObject::Messages::DefineProperty_NotWritable);
|
||||
}
|
||||
}
|
||||
|
||||
void Object::throwCannotDefineError(ExecutionState& state, const ObjectStructurePropertyName& P)
|
||||
{
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, P.toExceptionString(), false, String::emptyString, ErrorObject::Messages::DefineProperty_RedefineNotConfigurable);
|
||||
THROW_BUILTIN_ERROR_RETURN(state, ErrorCode::TypeError, P.toExceptionString(), false, String::emptyString, ErrorObject::Messages::DefineProperty_RedefineNotConfigurable);
|
||||
}
|
||||
|
||||
void Object::throwCannotWriteError(ExecutionState& state, const ObjectStructurePropertyName& P)
|
||||
{
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, P.toExceptionString(), false, String::emptyString, ErrorObject::Messages::DefineProperty_NotWritable);
|
||||
THROW_BUILTIN_ERROR_RETURN(state, ErrorCode::TypeError, P.toExceptionString(), false, String::emptyString, ErrorObject::Messages::DefineProperty_NotWritable);
|
||||
}
|
||||
|
||||
void Object::throwCannotDeleteError(ExecutionState& state, const ObjectStructurePropertyName& P)
|
||||
{
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, P.toExceptionString(), false, String::emptyString, ErrorObject::Messages::DefineProperty_NotConfigurable);
|
||||
THROW_BUILTIN_ERROR_RETURN(state, ErrorCode::TypeError, P.toExceptionString(), false, String::emptyString, ErrorObject::Messages::DefineProperty_NotConfigurable);
|
||||
}
|
||||
|
||||
ArrayObject* Object::createArrayFromList(ExecutionState& state, const uint64_t& size, const Value* buffer)
|
||||
|
|
@ -1544,11 +1563,15 @@ ValueVector Object::createListFromArrayLike(ExecutionState& state, Value obj, ui
|
|||
// If Type(obj) is not Object, throw a TypeError exception.
|
||||
if (!obj.isObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_FirstArgumentNotObject);
|
||||
return ValueVector();
|
||||
}
|
||||
|
||||
// Let len be ? LengthOfArrayLike(obj).
|
||||
Object* o = obj.asObject();
|
||||
auto len = o->length(state);
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
return ValueVector();
|
||||
}
|
||||
|
||||
// Let list be an empty List.
|
||||
// Let index be 0.
|
||||
|
|
@ -1560,6 +1583,9 @@ ValueVector Object::createListFromArrayLike(ExecutionState& state, Value obj, ui
|
|||
while (index < len) {
|
||||
// Let next be Get(obj, indexName).
|
||||
Value next = o->getIndexedProperty(state, Value(index)).value(state, o);
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
return ValueVector();
|
||||
}
|
||||
|
||||
// If Type(next) is not an element of elementTypes, throw a TypeError exception.
|
||||
bool validType = false;
|
||||
|
|
@ -1583,6 +1609,7 @@ ValueVector Object::createListFromArrayLike(ExecutionState& state, Value obj, ui
|
|||
|
||||
if (UNLIKELY(!validType)) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->object.string(), false, String::emptyString, "%s: Type(next) is not an element of elementTypes");
|
||||
return ValueVector();
|
||||
}
|
||||
|
||||
// Append next as the last element of list.
|
||||
|
|
@ -1633,7 +1660,9 @@ void Object::redefineOwnProperty(ExecutionState& state, const ObjectPropertyName
|
|||
uint64_t Object::length(ExecutionState& state)
|
||||
{
|
||||
// ToLength(Get(obj, "length"))
|
||||
return get(state, state.context()->staticStrings().length).value(state, this).toLength(state);
|
||||
Value len = get(state, state.context()->staticStrings().length).value(state, this);
|
||||
RETURN_ZERO_IF_PENDING_EXCEPTION
|
||||
return len.toLength(state);
|
||||
}
|
||||
|
||||
bool Object::isArray(ExecutionState& state)
|
||||
|
|
@ -1644,8 +1673,7 @@ bool Object::isArray(ExecutionState& state)
|
|||
if (isProxyObject()) {
|
||||
ProxyObject* proxy = asProxyObject();
|
||||
if (proxy->handler() == nullptr) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().Proxy.string(), false, String::emptyString, "%s: Proxy handler should not null.");
|
||||
return false;
|
||||
THROW_BUILTIN_ERROR_RETURN_ZERO(state, ErrorCode::TypeError, state.context()->staticStrings().Proxy.string(), false, String::emptyString, "%s: Proxy handler should not null.");
|
||||
}
|
||||
if (proxy->target() == nullptr) {
|
||||
return false;
|
||||
|
|
@ -1763,6 +1791,7 @@ void Object::sort(ExecutionState& state, int64_t length, const std::function<boo
|
|||
int64_t i;
|
||||
for (i = 0; i < n; i++) {
|
||||
setThrowsException(state, ObjectPropertyName(state, Value(i)), selected[i], this);
|
||||
RETURN_IF_PENDING_EXCEPTION
|
||||
}
|
||||
|
||||
while (i < length) {
|
||||
|
|
@ -1858,7 +1887,7 @@ static void addPrivateMember(ExecutionState& state, ObjectExtendedExtraData* e,
|
|||
ObjectPrivateMemberDataChain* piece = ensurePieceOnPrivateMemberChain(state, e, contextObject);
|
||||
|
||||
if (piece->m_privateMemberStructure->findProperty(propertyName)) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::CanNotRedefinePrivateMember, propertyName.string());
|
||||
THROW_BUILTIN_ERROR_RETURN(state, ErrorCode::TypeError, ErrorObject::Messages::CanNotRedefinePrivateMember, propertyName.string());
|
||||
}
|
||||
|
||||
piece->m_privateMemberStructure = piece->m_privateMemberStructure->addProperty(ObjectPrivateMemberStructureItem(propertyName, kind));
|
||||
|
|
@ -1898,7 +1927,7 @@ void Object::addPrivateAccessor(ExecutionState& state, Object* contextObject, At
|
|||
}
|
||||
}
|
||||
}
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Cannot add private field %s with same name twice", propertyName.string());
|
||||
THROW_BUILTIN_ERROR_RETURN(state, ErrorCode::TypeError, "Cannot add private field %s with same name twice", propertyName.string());
|
||||
} else {
|
||||
JSGetterSetter* gs = new JSGetterSetter(isGetter ? callback : Value(Value::EmptyValue), isSetter ? callback : Value(Value::EmptyValue));
|
||||
piece->m_privateMemberStructure = piece->m_privateMemberStructure->addProperty(
|
||||
|
|
@ -1930,7 +1959,7 @@ Value Object::getPrivateMember(ExecutionState& state, Object* contextObject, Ato
|
|||
if (desc.kind() == ObjectPrivateMemberStructureItemKind::GetterSetter) {
|
||||
JSGetterSetter* gs = Value(piece->m_privateMemberValues[r.value()]).asPointerValue()->asJSGetterSetter();
|
||||
if (!gs->hasGetter()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "'%s' was defined without a getter", propertyName.string());
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "'%s' was defined without a getter", propertyName.string());
|
||||
} else {
|
||||
return Object::call(state, gs->getter(), this, 0, nullptr);
|
||||
}
|
||||
|
|
@ -1941,8 +1970,7 @@ Value Object::getPrivateMember(ExecutionState& state, Object* contextObject, Ato
|
|||
} else if (shouldReferOuterClass && contextObject->asScriptClassConstructorFunctionObject()->outerClassConstructor()) {
|
||||
return getPrivateMember(state, contextObject->asScriptClassConstructorFunctionObject()->outerClassConstructor().value(), propertyName);
|
||||
}
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::CanNotReadPrivateMember, propertyName.string());
|
||||
return Value();
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::CanNotReadPrivateMember, propertyName.string());
|
||||
}
|
||||
|
||||
bool Object::hasPrivateMember(ExecutionState& state, Object* contextObject, AtomicString propertyName, bool shouldReferOuterClass)
|
||||
|
|
@ -1968,14 +1996,14 @@ void Object::setPrivateMember(ExecutionState& state, Object* contextObject, Atom
|
|||
if (desc.kind() == ObjectPrivateMemberStructureItemKind::GetterSetter) {
|
||||
JSGetterSetter* gs = Value(piece->m_privateMemberValues[r.value()]).asPointerValue()->asJSGetterSetter();
|
||||
if (!gs->hasSetter()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "'%s' was defined without a setter", propertyName.string());
|
||||
THROW_BUILTIN_ERROR_RETURN(state, ErrorCode::TypeError, "'%s' was defined without a setter", propertyName.string());
|
||||
} else {
|
||||
Value argv = value;
|
||||
Object::call(state, gs->setter(), this, 1, &argv);
|
||||
return;
|
||||
}
|
||||
} else if (desc.kind() == ObjectPrivateMemberStructureItemKind::Method) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "'%s' is non writable private property", propertyName.string());
|
||||
THROW_BUILTIN_ERROR_RETURN(state, ErrorCode::TypeError, "'%s' is non writable private property", propertyName.string());
|
||||
} else {
|
||||
piece->m_privateMemberValues[r.value()] = value;
|
||||
return;
|
||||
|
|
@ -1984,7 +2012,7 @@ void Object::setPrivateMember(ExecutionState& state, Object* contextObject, Atom
|
|||
} else if (shouldReferOuterClass && contextObject->asScriptClassConstructorFunctionObject()->outerClassConstructor()) {
|
||||
return setPrivateMember(state, contextObject->asScriptClassConstructorFunctionObject()->outerClassConstructor().value(), propertyName, value);
|
||||
}
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::CanNotWritePrivateMember, propertyName.string());
|
||||
THROW_BUILTIN_ERROR_RETURN(state, ErrorCode::TypeError, ErrorObject::Messages::CanNotWritePrivateMember, propertyName.string());
|
||||
}
|
||||
|
||||
IteratorObject* Object::values(ExecutionState& state)
|
||||
|
|
@ -2093,16 +2121,18 @@ Value Object::speciesConstructor(ExecutionState& state, const Value& defaultCons
|
|||
{
|
||||
ASSERT(isObject());
|
||||
Value C = asObject()->get(state, state.context()->staticStrings().constructor).value(state, this);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
if (C.isUndefined()) {
|
||||
return defaultConstructor;
|
||||
}
|
||||
|
||||
if (!C.isObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "constructor is not an object");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "constructor is not an object");
|
||||
}
|
||||
|
||||
Value S = C.asObject()->get(state, ObjectPropertyName(state.context()->vmInstance()->globalSymbols().species)).value(state, C);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
if (S.isUndefinedOrNull()) {
|
||||
return defaultConstructor;
|
||||
|
|
@ -2112,13 +2142,14 @@ Value Object::speciesConstructor(ExecutionState& state, const Value& defaultCons
|
|||
return S;
|
||||
}
|
||||
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "invalid speciesConstructor return");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "invalid speciesConstructor return");
|
||||
return Value();
|
||||
}
|
||||
|
||||
bool Object::isRegExp(ExecutionState& state)
|
||||
{
|
||||
Value symbol = get(state, ObjectPropertyName(state.context()->vmInstance()->globalSymbols().match)).value(state, this);
|
||||
RETURN_ZERO_IF_PENDING_EXCEPTION
|
||||
if (!symbol.isUndefined()) {
|
||||
return symbol.toBoolean(state);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -918,6 +918,9 @@ public:
|
|||
void defineOwnPropertyThrowsException(ExecutionState& state, const ObjectPropertyName& P, const ObjectPropertyDescriptor& desc)
|
||||
{
|
||||
if (!defineOwnProperty(state, P, desc)) {
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
return;
|
||||
}
|
||||
throwCannotDefineError(state, P.toObjectStructurePropertyName(state));
|
||||
}
|
||||
}
|
||||
|
|
@ -925,6 +928,9 @@ public:
|
|||
void deleteOwnPropertyThrowsException(ExecutionState& state, const ObjectPropertyName& P)
|
||||
{
|
||||
if (!deleteOwnProperty(state, P)) {
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
return;
|
||||
}
|
||||
throwCannotDefineError(state, P.toObjectStructurePropertyName(state));
|
||||
}
|
||||
}
|
||||
|
|
@ -942,6 +948,9 @@ public:
|
|||
void setIndexedPropertyThrowsException(ExecutionState& state, const Value& property, const Value& value)
|
||||
{
|
||||
if (!setIndexedProperty(state, property, value, this)) {
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
return;
|
||||
}
|
||||
throwCannotDefineError(state, ObjectStructurePropertyName(state, property.toString(state)));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,23 +40,15 @@ DECLARE_SCRIPTSIMPLEFUNCTION_LIST(DEFINE_SCRIPTSIMPLEFUNCTION_TAGS);
|
|||
Value PointerValue::call(ExecutionState& state, const Value& thisValue, const size_t argc, Value* argv)
|
||||
{
|
||||
ASSERT(!isCallable());
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::NOT_Callable);
|
||||
ASSERT_NOT_REACHED();
|
||||
|
||||
// never get here. but I add return statement for removing compile warning
|
||||
return Value(Value::EmptyValue);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::NOT_Callable);
|
||||
}
|
||||
|
||||
Value PointerValue::construct(ExecutionState& state, const size_t argc, Value* argv, Object* newTarget)
|
||||
{
|
||||
ASSERT(!isConstructor());
|
||||
if (isFunctionObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::Not_Constructor_Function, asFunctionObject()->codeBlock()->functionName());
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::Not_Constructor_Function, asFunctionObject()->codeBlock()->functionName());
|
||||
}
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::Not_Constructor);
|
||||
ASSERT_NOT_REACHED();
|
||||
|
||||
// never get here. but I add return statement for removing compile warning
|
||||
return Value();
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::Not_Constructor);
|
||||
}
|
||||
} // namespace Escargot
|
||||
|
|
|
|||
|
|
@ -101,7 +101,9 @@ PromiseReaction::Capability PromiseObject::newPromiseCapability(ExecutionState&
|
|||
|
||||
// If IsConstructor(C) is false, throw a TypeError exception.
|
||||
if (!constructor->isConstructor()) {
|
||||
// return exception done!
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::Not_Constructor);
|
||||
return PromiseReaction::Capability();
|
||||
}
|
||||
|
||||
// Let promiseCapability be a new PromiseCapability { [[Promise]]: undefined, [[Resolve]]: undefined, [[Reject]]: undefined }.
|
||||
|
|
@ -116,20 +118,37 @@ PromiseReaction::Capability PromiseObject::newPromiseCapability(ExecutionState&
|
|||
|
||||
// Let promise be ? Construct(C, « executor »).
|
||||
Object* promise = nullptr;
|
||||
Value promiseValue;
|
||||
if (UNLIKELY(context->vmInstance()->isPromiseHookRegistered())) {
|
||||
// Note) parent promise is used only for PromiseHook (delivered as an argument here)
|
||||
Value arguments[] = { executor, parentPromise };
|
||||
promise = Object::construct(state, constructor, 2, arguments).toObject(state);
|
||||
promiseValue = Object::construct(state, constructor, 2, arguments);
|
||||
} else {
|
||||
Value arguments[] = { executor };
|
||||
promise = Object::construct(state, constructor, 1, arguments).toObject(state);
|
||||
promiseValue = Object::construct(state, constructor, 1, arguments);
|
||||
}
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
return PromiseReaction::Capability();
|
||||
}
|
||||
promise = promiseValue.toObject(state);
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
return PromiseReaction::Capability();
|
||||
}
|
||||
|
||||
Value resolveFunction = capability->get(state, strings->resolve).value(state, capability);
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
return PromiseReaction::Capability();
|
||||
}
|
||||
|
||||
Value rejectFunction = capability->get(state, strings->reject).value(state, capability);
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
return PromiseReaction::Capability();
|
||||
}
|
||||
|
||||
if (!resolveFunction.isCallable() || !rejectFunction.isCallable()) {
|
||||
// return exception done!
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Promise resolve or reject function is not callable");
|
||||
return PromiseReaction::Capability();
|
||||
}
|
||||
|
||||
return PromiseReaction::Capability(promise, resolveFunction.asObject(), rejectFunction.asObject());
|
||||
|
|
@ -165,6 +184,9 @@ PromiseReaction::Capability PromiseObject::newPromiseResultCapability(ExecutionS
|
|||
{
|
||||
// Let C be ? SpeciesConstructor(promise, %Promise%).
|
||||
Value C = speciesConstructor(state, state.context()->globalObject()->promise());
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
return PromiseReaction::Capability();
|
||||
}
|
||||
// Let resultCapability be ? NewPromiseCapability(C).
|
||||
return PromiseObject::newPromiseCapability(state, C.toObject(state), this);
|
||||
}
|
||||
|
|
@ -238,16 +260,20 @@ Object* PromiseObject::promiseResolve(ExecutionState& state, Object* C, const Va
|
|||
if (x.isObject() && x.asObject()->isPromiseObject()) {
|
||||
// Let xConstructor be ? Get(x, "constructor").
|
||||
// If SameValue(xConstructor, C) is true, return x.
|
||||
if (x.asObject()->get(state, state.context()->staticStrings().constructor).value(state, x.asObject()) == Value(C)) {
|
||||
Value val = x.asObject()->get(state, state.context()->staticStrings().constructor).value(state, x.asObject());
|
||||
RETURN_NULL_IF_PENDING_EXCEPTION
|
||||
if (val == Value(C)) {
|
||||
return x.asObject()->asPromiseObject();
|
||||
}
|
||||
}
|
||||
// Let promiseCapability be ? NewPromiseCapability(C).
|
||||
PromiseReaction::Capability capability = PromiseObject::newPromiseCapability(state, C);
|
||||
RETURN_NULL_IF_PENDING_EXCEPTION
|
||||
|
||||
// Perform ? Call(promiseCapability.[[Resolve]], undefined, « x »).
|
||||
Value arguments[] = { x };
|
||||
Object::call(state, capability.m_resolveFunction, Value(), 1, arguments);
|
||||
RETURN_NULL_IF_PENDING_EXCEPTION
|
||||
// Return promiseCapability.[[Promise]].
|
||||
return capability.m_promise;
|
||||
}
|
||||
|
|
@ -268,7 +294,7 @@ Value PromiseObject::getCapabilitiesExecutorFunction(ExecutionState& state, Valu
|
|||
// If promiseCapability.[[Reject]] is not undefined, throw a TypeError exception.
|
||||
if (!capability->getOwnProperty(state, strings->resolve).value(state, capability).isUndefined()
|
||||
|| !capability->getOwnProperty(state, strings->reject).value(state, capability).isUndefined()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Executor function has already called");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "Executor function has already called");
|
||||
}
|
||||
|
||||
// Set promiseCapability.[[Resolve]] to resolve.
|
||||
|
|
@ -301,7 +327,9 @@ static Value promiseResolveFunctions(ExecutionState& state, Value thisValue, siz
|
|||
Object* alreadyResolved = alreadyResolvedValue.asObject();
|
||||
|
||||
// If alreadyResolved.[[Value]] is true, return undefined.
|
||||
if (alreadyResolved->getOwnProperty(state, strings->value).value(state, alreadyResolved).isTrue()) {
|
||||
Value val = alreadyResolved->getOwnProperty(state, strings->value).value(state, alreadyResolved);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (val.isTrue()) {
|
||||
return Value();
|
||||
}
|
||||
// Set alreadyResolved.[[Value]] to true.
|
||||
|
|
@ -319,11 +347,9 @@ static Value promiseResolveFunctions(ExecutionState& state, Value thisValue, siz
|
|||
}
|
||||
Object* resolution = resolutionValue.asObject();
|
||||
|
||||
Value then;
|
||||
try {
|
||||
then = resolution->get(state, strings->then).value(state, resolution);
|
||||
} catch (const Value& v) {
|
||||
Value reason = v;
|
||||
Value then = resolution->get(state, strings->then).value(state, resolution);
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
Value reason = state.detachPendingException();
|
||||
promise->reject(state, reason);
|
||||
return Value();
|
||||
}
|
||||
|
|
@ -357,7 +383,9 @@ static Value promiseRejectFunctions(ExecutionState& state, Value thisValue, size
|
|||
Object* alreadyResolved = alreadyResolvedValue.asObject();
|
||||
|
||||
// If alreadyResolved.[[Value]] is true, return undefined.
|
||||
if (alreadyResolved->getOwnProperty(state, strings->value).value(state, alreadyResolved).isTrue()) {
|
||||
Value val = alreadyResolved->getOwnProperty(state, strings->value).value(state, alreadyResolved);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (val.isTrue()) {
|
||||
return Value();
|
||||
}
|
||||
|
||||
|
|
@ -419,8 +447,7 @@ static Value ValueThunkThrower(ExecutionState& state, Value thisValue, size_t ar
|
|||
// Let F be the active function object.
|
||||
Object* F = state.resolveCallee();
|
||||
// Throw the resolve's member value
|
||||
state.throwException(F->asExtendedNativeFunctionObject()->internalSlot(PromiseObject::BuiltinFunctionSlot::ValueOrReason));
|
||||
return Value();
|
||||
THROW_EXCEPTION_RETURN_VALUE(state, F->asExtendedNativeFunctionObject()->internalSlot(PromiseObject::BuiltinFunctionSlot::ValueOrReason));
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -437,6 +464,7 @@ Value PromiseObject::promiseThenFinally(ExecutionState& state, Value thisValue,
|
|||
// Let result be ? Call(onFinally, undefined).
|
||||
ASSERT(onFinally.isCallable());
|
||||
Value result = Object::call(state, onFinally, Value(), 0, nullptr);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// Let C be F.[[Constructor]].
|
||||
// Assert: IsConstructor(C) is true.
|
||||
|
|
@ -445,6 +473,7 @@ Value PromiseObject::promiseThenFinally(ExecutionState& state, Value thisValue,
|
|||
|
||||
// Let promise be ? PromiseResolve(C, result).
|
||||
Value promise = PromiseObject::promiseResolve(state, C.asObject(), result);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// Let valueThunk be equivalent to a function that returns value.
|
||||
ExtendedNativeFunctionObject* valueThunk = new ExtendedNativeFunctionObjectImpl<1>(state, NativeFunctionInfo(AtomicString(), ValueThunkHelper, 0, NativeFunctionInfo::Strict));
|
||||
|
|
@ -452,6 +481,7 @@ Value PromiseObject::promiseThenFinally(ExecutionState& state, Value thisValue,
|
|||
|
||||
// Return ? Invoke(promise, "then", « valueThunk »).
|
||||
Value then = promise.asObject()->get(state, strings->then).value(state, promise);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
Value argument[1] = { Value(valueThunk) };
|
||||
|
||||
return Object::call(state, then, promise, 1, argument);
|
||||
|
|
@ -471,6 +501,7 @@ Value PromiseObject::promiseCatchFinally(ExecutionState& state, Value thisValue,
|
|||
// Let result be ? Call(onFinally, undefined).
|
||||
ASSERT(onFinally.isCallable());
|
||||
Value result = Object::call(state, onFinally, Value(), 0, nullptr);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// Let C be F.[[Constructor]].
|
||||
// Assert: IsConstructor(C) is true.
|
||||
|
|
@ -479,6 +510,7 @@ Value PromiseObject::promiseCatchFinally(ExecutionState& state, Value thisValue,
|
|||
|
||||
// Let promise be ? PromiseResolve(C, result).
|
||||
Value promise = PromiseObject::promiseResolve(state, C.asObject(), result);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// Let thrower be equivalent to a function that throws reason.
|
||||
ExtendedNativeFunctionObject* valueThunk = new ExtendedNativeFunctionObjectImpl<1>(state, NativeFunctionInfo(AtomicString(), ValueThunkThrower, 0, NativeFunctionInfo::Strict));
|
||||
|
|
@ -486,6 +518,7 @@ Value PromiseObject::promiseCatchFinally(ExecutionState& state, Value thisValue,
|
|||
|
||||
// Return ? Invoke(promise, "then", « thrower »).
|
||||
Value then = promise.asObject()->get(state, strings->then).value(state, promise);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
Value argument[1] = { Value(valueThunk) };
|
||||
|
||||
return Object::call(state, then, promise, 1, argument);
|
||||
|
|
@ -607,6 +640,7 @@ Value PromiseObject::promiseAnyRejectElementFunction(ExecutionState& state, Valu
|
|||
error->defineOwnPropertyThrowsException(state, ObjectPropertyName(state, String::fromASCII("errors")),
|
||||
ObjectPropertyDescriptor(Object::createArrayFromList(state, *errors),
|
||||
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::ConfigurablePresent | ObjectPropertyDescriptor::WritablePresent)));
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Return ? Call(promiseCapability.[[Reject]], undefined, « error »).
|
||||
Value argv = error;
|
||||
return Object::call(state, F->internalSlot(BuiltinFunctionSlot::Reject), Value(), 1, &argv);
|
||||
|
|
|
|||
|
|
@ -52,8 +52,7 @@ void* ProxyObject::operator new(size_t size)
|
|||
Context* ProxyObject::getFunctionRealm(ExecutionState& state)
|
||||
{
|
||||
if (m_handler == nullptr) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().Proxy.string(), false, String::emptyString, "%s: Proxy handler should not be null.");
|
||||
return nullptr;
|
||||
THROW_BUILTIN_ERROR_RETURN_NULL(state, ErrorCode::TypeError, state.context()->staticStrings().Proxy.string(), false, String::emptyString, "%s: Proxy handler should not be null.");
|
||||
}
|
||||
|
||||
return m_target->getFunctionRealm(state);
|
||||
|
|
@ -67,12 +66,12 @@ ProxyObject* ProxyObject::createProxy(ExecutionState& state, const Value& target
|
|||
|
||||
// If Type(target) is not Object, throw a TypeError exception.
|
||||
if (!target.isObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString, "%s: \'target\' argument of Proxy must be an object");
|
||||
THROW_BUILTIN_ERROR_RETURN_NULL(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString, "%s: \'target\' argument of Proxy must be an object");
|
||||
}
|
||||
|
||||
// If Type(handler) is not Object, throw a TypeError exception.
|
||||
if (!handler.isObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString, "%s: \'handler\' argument of Proxy must be an object");
|
||||
THROW_BUILTIN_ERROR_RETURN_NULL(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString, "%s: \'handler\' argument of Proxy must be an object");
|
||||
}
|
||||
|
||||
// Let P be ! MakeBasicObject(« [[ProxyHandler]], [[ProxyTarget]] »).
|
||||
|
|
@ -105,8 +104,7 @@ bool ProxyObject::defineOwnProperty(ExecutionState& state, const ObjectPropertyN
|
|||
auto strings = &state.context()->staticStrings();
|
||||
// 3. If handler is null, throw a TypeError exception.
|
||||
if (this->handler() == nullptr) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString, "%s: Proxy handler should not be null.");
|
||||
return false;
|
||||
THROW_BUILTIN_ERROR_RETURN_ZERO(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString, "%s: Proxy handler should not be null.");
|
||||
}
|
||||
|
||||
// 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
|
||||
|
|
@ -122,6 +120,7 @@ bool ProxyObject::defineOwnProperty(ExecutionState& state, const ObjectPropertyN
|
|||
// 7. ReturnIfAbrupt(trap).
|
||||
Value trap;
|
||||
trap = Object::getMethod(state, handler, ObjectPropertyName(state, strings->defineProperty.string()));
|
||||
RETURN_ZERO_IF_PENDING_EXCEPTION
|
||||
|
||||
// 8. If trap is undefined, then
|
||||
// a. Return target.[[DefineOwnProperty]](P, Desc).
|
||||
|
|
@ -132,9 +131,10 @@ bool ProxyObject::defineOwnProperty(ExecutionState& state, const ObjectPropertyN
|
|||
// 9. Let descObj be FromPropertyDescriptor(Desc).
|
||||
// 10. Let booleanTrapResult be ToBoolean(Call(trap, handler, «target, P, descObj»)).
|
||||
// 11. ReturnIfAbrupt(booleanTrapResult).
|
||||
bool booleanTrapResult;
|
||||
Value arguments[] = { target, P.toPropertyKeyValue(), Value(ObjectPropertyDescriptor::fromObjectPropertyDescriptor(state, desc)) };
|
||||
booleanTrapResult = Object::call(state, trap, handler, 3, arguments).toBoolean(state);
|
||||
Value trapResult = Object::call(state, trap, handler, 3, arguments);
|
||||
RETURN_ZERO_IF_PENDING_EXCEPTION
|
||||
bool booleanTrapResult = trapResult.toBoolean(state);
|
||||
|
||||
// 12. If booleanTrapResult is false, return false.
|
||||
if (!booleanTrapResult) {
|
||||
|
|
@ -160,21 +160,18 @@ bool ProxyObject::defineOwnProperty(ExecutionState& state, const ObjectPropertyN
|
|||
// b. If settingConfigFalse is true, throw a TypeError exception.
|
||||
if (!targetDesc.hasValue()) {
|
||||
if (!extensibleTarget || settingConfigFalse) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString, "%s: Proxy Type Error");
|
||||
return false;
|
||||
THROW_BUILTIN_ERROR_RETURN_ZERO(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString, "%s: Proxy Type Error");
|
||||
}
|
||||
} else {
|
||||
// 20. Else targetDesc is not undefined,
|
||||
// a. If IsCompatiblePropertyDescriptor(extensibleTarget, Desc , targetDesc) is false, throw a TypeError exception.
|
||||
// b. If settingConfigFalse is true and targetDesc.[[Configurable]] is true, throw a TypeError exception.
|
||||
if (!Object::isCompatiblePropertyDescriptor(state, extensibleTarget, desc, targetDesc) || (settingConfigFalse && targetDesc.isConfigurable())) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString, "%s: Proxy Type Error");
|
||||
return false;
|
||||
THROW_BUILTIN_ERROR_RETURN_ZERO(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString, "%s: Proxy Type Error");
|
||||
}
|
||||
if (targetDesc.isDataProperty() && !targetDesc.isConfigurable() && targetDesc.isWritable()) {
|
||||
if (desc.isWritablePresent() && !desc.isWritable()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString, "%s: Proxy Type Error");
|
||||
return false;
|
||||
THROW_BUILTIN_ERROR_RETURN_ZERO(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString, "%s: Proxy Type Error");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -187,8 +184,7 @@ bool ProxyObject::deleteOwnProperty(ExecutionState& state, const ObjectPropertyN
|
|||
auto strings = &state.context()->staticStrings();
|
||||
// 3. If handler is null, throw a TypeError exception.
|
||||
if (this->handler() == nullptr) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString, "%s: Proxy handler should not be null.");
|
||||
return false;
|
||||
THROW_BUILTIN_ERROR_RETURN_ZERO(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString, "%s: Proxy handler should not be null.");
|
||||
}
|
||||
|
||||
// 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
|
||||
|
|
@ -204,6 +200,7 @@ bool ProxyObject::deleteOwnProperty(ExecutionState& state, const ObjectPropertyN
|
|||
// 7. ReturnIfAbrupt(trap).
|
||||
Value trap;
|
||||
trap = Object::getMethod(state, handler, ObjectPropertyName(state, strings->deleteProperty.string()));
|
||||
RETURN_ZERO_IF_PENDING_EXCEPTION
|
||||
|
||||
// 8. If trap is undefined, then
|
||||
// a. Return target.[[Delete]](P).
|
||||
|
|
@ -213,9 +210,10 @@ bool ProxyObject::deleteOwnProperty(ExecutionState& state, const ObjectPropertyN
|
|||
|
||||
// 9. Let booleanTrapResult be ToBoolean(Call(trap, handler, «target, P»)).
|
||||
// 10. ReturnIfAbrupt(booleanTrapResult).
|
||||
bool booleanTrapResult;
|
||||
Value arguments[] = { target, P.toPropertyKeyValue() };
|
||||
booleanTrapResult = Object::call(state, trap, handler, 2, arguments).toBoolean(state);
|
||||
Value trapResult = Object::call(state, trap, handler, 2, arguments);
|
||||
RETURN_ZERO_IF_PENDING_EXCEPTION
|
||||
bool booleanTrapResult = trapResult.toBoolean(state);
|
||||
|
||||
// 11. If booleanTrapResult is false, return false.
|
||||
if (!booleanTrapResult) {
|
||||
|
|
@ -232,12 +230,10 @@ bool ProxyObject::deleteOwnProperty(ExecutionState& state, const ObjectPropertyN
|
|||
|
||||
// 15. If targetDesc.[[Configurable]] is false, throw a TypeError exception.
|
||||
if (!targetDesc.isConfigurable()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString, "%s: Proxy Type Error");
|
||||
return false;
|
||||
THROW_BUILTIN_ERROR_RETURN_ZERO(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString, "%s: Proxy Type Error");
|
||||
}
|
||||
if (!target.asObject()->isExtensible(state)) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString, "%s: Proxy Type Error");
|
||||
return false;
|
||||
THROW_BUILTIN_ERROR_RETURN_ZERO(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString, "%s: Proxy Type Error");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
@ -247,6 +243,7 @@ ObjectGetResult ProxyObject::getOwnProperty(ExecutionState& state, const ObjectP
|
|||
auto strings = &state.context()->staticStrings();
|
||||
// 3. If handler is null, throw a TypeError exception.
|
||||
if (this->handler() == nullptr) {
|
||||
// return exception done!
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString, "%s: Proxy handler should not be null.");
|
||||
return ObjectGetResult();
|
||||
}
|
||||
|
|
@ -264,6 +261,9 @@ ObjectGetResult ProxyObject::getOwnProperty(ExecutionState& state, const ObjectP
|
|||
// 7. ReturnIfAbrupt(trap).
|
||||
Value trap;
|
||||
trap = Object::getMethod(state, handler, ObjectPropertyName(state, strings->getOwnPropertyDescriptor.string()));
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
return ObjectGetResult();
|
||||
}
|
||||
|
||||
// 8. If trap is undefined, then
|
||||
// a. Return target.[[GetOwnProperty]](P).
|
||||
|
|
@ -276,9 +276,13 @@ ObjectGetResult ProxyObject::getOwnProperty(ExecutionState& state, const ObjectP
|
|||
Value trapResultObj;
|
||||
Value arguments[] = { target, P.toPropertyKeyValue() };
|
||||
trapResultObj = Object::call(state, trap, handler, 2, arguments);
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
return ObjectGetResult();
|
||||
}
|
||||
|
||||
// 11. If Type(trapResultObj) is neither Object nor Undefined, throw a TypeError exception.
|
||||
if (!trapResultObj.isObject() && !trapResultObj.isUndefined()) {
|
||||
// return exception done!
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString, "%s: Proxy Type Error");
|
||||
return ObjectGetResult();
|
||||
}
|
||||
|
|
@ -294,6 +298,7 @@ ObjectGetResult ProxyObject::getOwnProperty(ExecutionState& state, const ObjectP
|
|||
}
|
||||
// b. If targetDesc.[[Configurable]] is false, throw a TypeError exception.
|
||||
if (!targetDesc.isConfigurable()) {
|
||||
// return exception done!
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString, "%s: Proxy Type Error");
|
||||
return ObjectGetResult();
|
||||
}
|
||||
|
|
@ -303,6 +308,7 @@ ObjectGetResult ProxyObject::getOwnProperty(ExecutionState& state, const ObjectP
|
|||
bool extensibleTarget = target.asObject()->isExtensible(state);
|
||||
// f. If extensibleTarget is false, throw a TypeError exception.
|
||||
if (!extensibleTarget) {
|
||||
// return exception done!
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString, "%s: Proxy Type Error");
|
||||
return ObjectGetResult();
|
||||
}
|
||||
|
|
@ -319,17 +325,23 @@ ObjectGetResult ProxyObject::getOwnProperty(ExecutionState& state, const ObjectP
|
|||
// 20. Let valid be IsCompatiblePropertyDescriptor (extensibleTarget, resultDesc, targetDesc).
|
||||
// 21. If valid is false, throw a TypeError exception.
|
||||
if (!Object::isCompatiblePropertyDescriptor(state, target.asObject()->isExtensible(state), resultDesc, targetDesc)) {
|
||||
// return exception done!
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Proxy::getOwnPropertyDescriptor error");
|
||||
return ObjectGetResult();
|
||||
}
|
||||
// 22. If resultDesc.[[Configurable]] is false, then
|
||||
if (!resultDesc.isConfigurable()) {
|
||||
// a. If targetDesc is undefined or targetDesc.[[Configurable]] is true, then
|
||||
if (!targetDesc.hasValue() || targetDesc.isConfigurable()) {
|
||||
// i. Throw a TypeError exception.
|
||||
// return exception done!
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Proxy::getOwnPropertyDescriptor error");
|
||||
return ObjectGetResult();
|
||||
}
|
||||
if (resultDesc.isWritablePresent() && !resultDesc.isWritable() && targetDesc.isWritable()) {
|
||||
// return exception done!
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Proxy::getOwnPropertyDescriptor error");
|
||||
return ObjectGetResult();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -345,8 +357,7 @@ bool ProxyObject::preventExtensions(ExecutionState& state)
|
|||
auto strings = &state.context()->staticStrings();
|
||||
// 2. If handler is null, throw a TypeError exception.
|
||||
if (this->handler() == nullptr) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString, "%s: Proxy handler should not be null.");
|
||||
return false;
|
||||
THROW_BUILTIN_ERROR_RETURN_ZERO(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString, "%s: Proxy handler should not be null.");
|
||||
}
|
||||
|
||||
// 1. Let handler be the value of the [[ProxyHandler]] internal slot of O.
|
||||
|
|
@ -362,6 +373,7 @@ bool ProxyObject::preventExtensions(ExecutionState& state)
|
|||
// 6. ReturnIfAbrupt(trap).
|
||||
Value trap;
|
||||
trap = Object::getMethod(state, handler, ObjectPropertyName(state, strings->preventExtensions.string()));
|
||||
RETURN_ZERO_IF_PENDING_EXCEPTION
|
||||
|
||||
// 7. If trap is undefined, then
|
||||
// a. Return target.[[PreventExtensions]]().
|
||||
|
|
@ -371,9 +383,10 @@ bool ProxyObject::preventExtensions(ExecutionState& state)
|
|||
|
||||
// 8. Let booleanTrapResult be ToBoolean(Call(trap, handler, «target»)).
|
||||
// 9. ReturnIfAbrupt(booleanTrapResult).
|
||||
bool booleanTrapResult;
|
||||
Value arguments[] = { target };
|
||||
booleanTrapResult = Object::call(state, trap, handler, 1, arguments).toBoolean(state);
|
||||
Value trapResult = Object::call(state, trap, handler, 1, arguments);
|
||||
RETURN_ZERO_IF_PENDING_EXCEPTION
|
||||
bool booleanTrapResult = trapResult.toBoolean(state);
|
||||
|
||||
// 10. If booleanTrapResult is true, then
|
||||
if (booleanTrapResult) {
|
||||
|
|
@ -381,8 +394,7 @@ bool ProxyObject::preventExtensions(ExecutionState& state)
|
|||
bool targetIsExtensible = target.asObject()->isExtensible(state);
|
||||
// c. If targetIsExtensible is true, throw a TypeError exception.
|
||||
if (targetIsExtensible) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString, "%s: Proxy Type Error");
|
||||
return false;
|
||||
THROW_BUILTIN_ERROR_RETURN_ZERO(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString, "%s: Proxy Type Error");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -392,12 +404,13 @@ bool ProxyObject::preventExtensions(ExecutionState& state)
|
|||
|
||||
ObjectHasPropertyResult ProxyObject::hasProperty(ExecutionState& state, const ObjectPropertyName& propertyName)
|
||||
{
|
||||
CHECK_STACK_OVERFLOW(state);
|
||||
//CHECK_STACK_OVERFLOW(state);
|
||||
|
||||
auto strings = &state.context()->staticStrings();
|
||||
|
||||
// 3. If handler is null, throw a TypeError exception.
|
||||
if (this->handler() == nullptr) {
|
||||
// return exception done!
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString, "%s: Proxy handler should not be null.");
|
||||
return ObjectHasPropertyResult();
|
||||
}
|
||||
|
|
@ -415,6 +428,9 @@ ObjectHasPropertyResult ProxyObject::hasProperty(ExecutionState& state, const Ob
|
|||
// 7. ReturnIfAbrupt(trap).
|
||||
Value trap;
|
||||
trap = Object::getMethod(state, handler, ObjectPropertyName(state, strings->has.string()));
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
return ObjectHasPropertyResult();
|
||||
}
|
||||
|
||||
// 8. If trap is undefined, then
|
||||
// a. Return target.[[HasProperty]](P).
|
||||
|
|
@ -433,9 +449,12 @@ ObjectHasPropertyResult ProxyObject::hasProperty(ExecutionState& state, const Ob
|
|||
|
||||
// 9. Let booleanTrapResult be ToBoolean(Call(trap, handler, «target, P»)).
|
||||
// 10. ReturnIfAbrupt(booleanTrapResult).
|
||||
bool booleanTrapResult;
|
||||
Value arguments[] = { target, propertyName.toPropertyKeyValue() };
|
||||
booleanTrapResult = Object::call(state, trap, handler, 2, arguments).toBoolean(state);
|
||||
Value trapResult = Object::call(state, trap, handler, 2, arguments);
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
return ObjectGetResult();
|
||||
}
|
||||
bool booleanTrapResult = trapResult.toBoolean(state);
|
||||
|
||||
// 11. If booleanTrapResult is false, then
|
||||
if (!booleanTrapResult) {
|
||||
|
|
@ -445,6 +464,7 @@ ObjectHasPropertyResult ProxyObject::hasProperty(ExecutionState& state, const Ob
|
|||
if (targetDesc.hasValue()) {
|
||||
// i. If targetDesc.[[Configurable]] is false, throw a TypeError exception.
|
||||
if (!targetDesc.isConfigurable()) {
|
||||
// return exception done!
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString, "%s: Proxy Type Error");
|
||||
return ObjectGetResult();
|
||||
}
|
||||
|
|
@ -452,6 +472,7 @@ ObjectHasPropertyResult ProxyObject::hasProperty(ExecutionState& state, const Ob
|
|||
bool extensibleTarget = target.asObject()->isExtensible(state);
|
||||
// iv. If extensibleTarget is false, throw a TypeError exception.
|
||||
if (!extensibleTarget) {
|
||||
// return exception done!
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString, "%s: Proxy Type Error");
|
||||
return ObjectGetResult();
|
||||
}
|
||||
|
|
@ -477,6 +498,7 @@ Object::OwnPropertyKeyVector ProxyObject::ownPropertyKeys(ExecutionState& state)
|
|||
// 1. Let handler be the value of the [[ProxyHandler]] internal slot of O.
|
||||
// 2. If handler is null, throw a TypeError exception.
|
||||
if (this->handler() == nullptr) {
|
||||
// return exception done!
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString, "%s: Proxy handler should not be null.");
|
||||
return OwnPropertyKeyVector();
|
||||
}
|
||||
|
|
@ -492,6 +514,9 @@ Object::OwnPropertyKeyVector ProxyObject::ownPropertyKeys(ExecutionState& state)
|
|||
// 6. ReturnIfAbrupt(trap).
|
||||
Value trap;
|
||||
trap = Object::getMethod(state, handler, ObjectPropertyName(state, strings->ownKeys));
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
return OwnPropertyKeyVector();
|
||||
}
|
||||
|
||||
// 7. If trap is undefined, then
|
||||
// a. Return target.[[OwnPropertyKeys]]().
|
||||
|
|
@ -505,13 +530,22 @@ Object::OwnPropertyKeyVector ProxyObject::ownPropertyKeys(ExecutionState& state)
|
|||
Value trapResultArray;
|
||||
Value arguments[] = { target };
|
||||
trapResultArray = Object::call(state, trap, handler, 1, arguments);
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
return OwnPropertyKeyVector();
|
||||
}
|
||||
|
||||
auto trapResult = Object::createListFromArrayLike(state, trapResultArray, (static_cast<uint8_t>(ElementTypes::String) | static_cast<uint8_t>(ElementTypes::Symbol)));
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
return OwnPropertyKeyVector();
|
||||
}
|
||||
|
||||
// If trapResult contains any duplicate entries, throw a TypeError exception
|
||||
for (size_t i = 0; i < trapResult.size(); i++) {
|
||||
for (size_t j = i + 1; j < trapResult.size(); j++) {
|
||||
if (trapResult[i].equalsTo(state, trapResult[j])) {
|
||||
// return exception done!
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString, "%s Contains duplacted entries.");
|
||||
return OwnPropertyKeyVector();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -576,6 +610,7 @@ Object::OwnPropertyKeyVector ProxyObject::ownPropertyKeys(ExecutionState& state)
|
|||
}
|
||||
if (!found) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString, "%s: the key of targetNonconfigurableKeys is not an element of uncheckedResultKeys.");
|
||||
return OwnPropertyKeyVector();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -599,11 +634,13 @@ Object::OwnPropertyKeyVector ProxyObject::ownPropertyKeys(ExecutionState& state)
|
|||
}
|
||||
if (!found) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString, "%s: the key of targetConfigurableKeys is not an element of uncheckedResultKeys.");
|
||||
return OwnPropertyKeyVector();
|
||||
}
|
||||
}
|
||||
// 24. If uncheckedResultKeys is not empty, throw a TypeError exception.
|
||||
if (uncheckedResultKeys.size()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString, "%s: uncheckedResultKeys is not empty");
|
||||
return OwnPropertyKeyVector();
|
||||
}
|
||||
|
||||
// 25. Return trapResult.
|
||||
|
|
@ -612,13 +649,12 @@ Object::OwnPropertyKeyVector ProxyObject::ownPropertyKeys(ExecutionState& state)
|
|||
|
||||
bool ProxyObject::isExtensible(ExecutionState& state)
|
||||
{
|
||||
CHECK_STACK_OVERFLOW(state);
|
||||
//CHECK_STACK_OVERFLOW(state);
|
||||
|
||||
auto strings = &state.context()->staticStrings();
|
||||
// 2. If handler is null, throw a TypeError exception.
|
||||
if (this->handler() == nullptr) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString, "%s: Proxy handler should not be null.");
|
||||
return false;
|
||||
THROW_BUILTIN_ERROR_RETURN_ZERO(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString, "%s: Proxy handler should not be null.");
|
||||
}
|
||||
|
||||
// 1. Let handler be the value of the [[ProxyHandler]] internal slot of O.
|
||||
|
|
@ -634,6 +670,7 @@ bool ProxyObject::isExtensible(ExecutionState& state)
|
|||
// 6. ReturnIfAbrupt(trap).
|
||||
Value trap;
|
||||
trap = Object::getMethod(state, handler, ObjectPropertyName(state, strings->isExtensible.string()));
|
||||
RETURN_ZERO_IF_PENDING_EXCEPTION
|
||||
|
||||
// 7. If trap is undefined, then
|
||||
// a. Return target.[[IsExtensible]]().
|
||||
|
|
@ -643,17 +680,17 @@ bool ProxyObject::isExtensible(ExecutionState& state)
|
|||
|
||||
// 8. Let booleanTrapResult be ToBoolean(Call(trap, handler, «target»)).
|
||||
// 9. ReturnIfAbrupt(booleanTrapResult).
|
||||
bool booleanTrapResult;
|
||||
Value arguments[] = { target };
|
||||
booleanTrapResult = Object::call(state, trap, handler, 1, arguments).toBoolean(state);
|
||||
Value trapResult = Object::call(state, trap, handler, 1, arguments);
|
||||
RETURN_ZERO_IF_PENDING_EXCEPTION
|
||||
bool booleanTrapResult = trapResult.toBoolean(state);
|
||||
|
||||
// 10. Let targetResult be target.[[IsExtensible]]().
|
||||
bool targetResult = target.asObject()->isExtensible(state);
|
||||
|
||||
// 12. If SameValue(booleanTrapResult, targetResult) is false, throw a TypeError exception.
|
||||
if (targetResult != booleanTrapResult) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString, "%s: Proxy Type Error");
|
||||
return false;
|
||||
THROW_BUILTIN_ERROR_RETURN_ZERO(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString, "%s: Proxy Type Error");
|
||||
}
|
||||
// 13. Return booleanTrapResult.
|
||||
return booleanTrapResult;
|
||||
|
|
@ -669,7 +706,7 @@ void ProxyObject::enumeration(ExecutionState& state, bool (*callback)(ExecutionS
|
|||
// https://www.ecma-international.org/ecma-262/6.0/#sec-proxy-object-internal-methods-and-internal-slots-setprototypeof-v
|
||||
bool ProxyObject::setPrototype(ExecutionState& state, const Value& value)
|
||||
{
|
||||
CHECK_STACK_OVERFLOW(state);
|
||||
//CHECK_STACK_OVERFLOW(state);
|
||||
|
||||
auto strings = &state.context()->staticStrings();
|
||||
// 1. Assert: Either Type(V) is Object or Type(V) is Null.
|
||||
|
|
@ -677,8 +714,7 @@ bool ProxyObject::setPrototype(ExecutionState& state, const Value& value)
|
|||
|
||||
// 3. If handler is null, throw a TypeError exception.
|
||||
if (this->handler() == nullptr) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString, "%s: Proxy handler should not be null.");
|
||||
return false;
|
||||
THROW_BUILTIN_ERROR_RETURN_ZERO(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString, "%s: Proxy handler should not be null.");
|
||||
}
|
||||
|
||||
// 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
|
||||
|
|
@ -694,6 +730,7 @@ bool ProxyObject::setPrototype(ExecutionState& state, const Value& value)
|
|||
// 7. ReturnIfAbrupt(trap).
|
||||
Value trap;
|
||||
trap = Object::getMethod(state, handler, ObjectPropertyName(state, strings->setPrototypeOf.string()));
|
||||
RETURN_ZERO_IF_PENDING_EXCEPTION
|
||||
|
||||
// 8. If trap is undefined, then
|
||||
// a. Return target.[[SetPrototypeOf]](V).
|
||||
|
|
@ -703,9 +740,10 @@ bool ProxyObject::setPrototype(ExecutionState& state, const Value& value)
|
|||
|
||||
// 9. Let booleanTrapResult be ToBoolean(Call(trap, handler, «target, V»)).
|
||||
// 10. ReturnIfAbrupt(booleanTrapResult).
|
||||
bool booleanTrapResult;
|
||||
Value arguments[] = { target, value };
|
||||
booleanTrapResult = Object::call(state, trap, handler, 2, arguments).toBoolean(state);
|
||||
Value trapResult = Object::call(state, trap, handler, 2, arguments);
|
||||
RETURN_ZERO_IF_PENDING_EXCEPTION
|
||||
bool booleanTrapResult = trapResult.toBoolean(state);
|
||||
|
||||
// For ES2018 compatibility 9.5.2.9
|
||||
if (!booleanTrapResult) {
|
||||
|
|
@ -722,11 +760,11 @@ bool ProxyObject::setPrototype(ExecutionState& state, const Value& value)
|
|||
|
||||
// 14. Let targetProto be target.[[GetPrototypeOf]]().
|
||||
Value targetProto = target.asObject()->getPrototype(state);
|
||||
RETURN_ZERO_IF_PENDING_EXCEPTION
|
||||
|
||||
// 16. If booleanTrapResult is true and SameValue(V, targetProto) is false, throw a TypeError exception.
|
||||
if (booleanTrapResult && value != targetProto) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString, "%s: Proxy Type Error");
|
||||
return false;
|
||||
THROW_BUILTIN_ERROR_RETURN_ZERO(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString, "%s: Proxy Type Error");
|
||||
}
|
||||
|
||||
// 17. Return booleanTrapResult.
|
||||
|
|
@ -740,6 +778,7 @@ Object* ProxyObject::getPrototypeObject(ExecutionState& state)
|
|||
}
|
||||
|
||||
Value result = getPrototype(state);
|
||||
RETURN_NULL_IF_PENDING_EXCEPTION
|
||||
if (result.isObject()) {
|
||||
return result.asObject();
|
||||
}
|
||||
|
|
@ -753,8 +792,7 @@ Value ProxyObject::getPrototype(ExecutionState& state)
|
|||
auto strings = &state.context()->staticStrings();
|
||||
// 2. If handler is null, throw a TypeError exception.
|
||||
if (this->handler() == nullptr) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString, "%s: Proxy handler should not be null.");
|
||||
return Value();
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString, "%s: Proxy handler should not be null.");
|
||||
}
|
||||
|
||||
// 1. Let handler be the value of the [[ProxyHandler]] internal slot of O.
|
||||
|
|
@ -770,6 +808,7 @@ Value ProxyObject::getPrototype(ExecutionState& state)
|
|||
// 6. ReturnIfAbrupt(trap).
|
||||
Value trap;
|
||||
trap = Object::getMethod(state, handler, ObjectPropertyName(state, strings->getPrototypeOf.string()));
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// 7. If trap is undefined, then
|
||||
// a. Return target.[[GetPrototypeOf]]().
|
||||
|
|
@ -782,11 +821,11 @@ Value ProxyObject::getPrototype(ExecutionState& state)
|
|||
Value handlerProto;
|
||||
Value arguments[] = { target };
|
||||
handlerProto = Object::call(state, trap, handler, 1, arguments);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// 10. If Type(handlerProto) is neither Object nor Null, throw a TypeError exception.
|
||||
if (!handlerProto.isObject() && !handlerProto.isNull()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString, "%s: Proxy Type Error");
|
||||
return Value();
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString, "%s: Proxy Type Error");
|
||||
}
|
||||
|
||||
// 11. Let extensibleTarget be IsExtensible(target).
|
||||
|
|
@ -799,11 +838,11 @@ Value ProxyObject::getPrototype(ExecutionState& state)
|
|||
|
||||
// 14. Let targetProto be target.[[GetPrototypeOf]]().
|
||||
Value targetProto = target.asObject()->getPrototype(state);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// 16. If SameValue(handlerProto, targetProto) is false, throw a TypeError exception.
|
||||
if (handlerProto != targetProto) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString, "%s: Proxy Type Error");
|
||||
return Value();
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString, "%s: Proxy Type Error");
|
||||
}
|
||||
|
||||
// 17. Return handlerProto.
|
||||
|
|
@ -813,7 +852,7 @@ Value ProxyObject::getPrototype(ExecutionState& state)
|
|||
// https://www.ecma-international.org/ecma-262/6.0/index.html#sec-proxy-object-internal-methods-and-internal-slots-get-p-receiver
|
||||
ObjectGetResult ProxyObject::get(ExecutionState& state, const ObjectPropertyName& propertyName, const Value& receiver)
|
||||
{
|
||||
CHECK_STACK_OVERFLOW(state);
|
||||
//CHECK_STACK_OVERFLOW(state);
|
||||
|
||||
auto strings = &state.context()->staticStrings();
|
||||
// 3. If handler is null, throw a TypeError exception.
|
||||
|
|
@ -835,6 +874,9 @@ ObjectGetResult ProxyObject::get(ExecutionState& state, const ObjectPropertyName
|
|||
// 7. ReturnIfAbrupt(trap).
|
||||
Value trap;
|
||||
trap = Object::getMethod(state, handler, ObjectPropertyName(state, strings->get.string()));
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
return ObjectGetResult();
|
||||
}
|
||||
|
||||
// 8. If trap is undefined, then
|
||||
// a. Return target.[[Get]](P, Receiver).
|
||||
|
|
@ -847,6 +889,9 @@ ObjectGetResult ProxyObject::get(ExecutionState& state, const ObjectPropertyName
|
|||
Value trapResult;
|
||||
Value arguments[] = { target, propertyName.toPropertyKeyValue(), Value(this) };
|
||||
trapResult = Object::call(state, trap, handler, 3, arguments);
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
return ObjectGetResult();
|
||||
}
|
||||
|
||||
// 11. Let targetDesc be target.[[GetOwnProperty]](P).
|
||||
ObjectGetResult targetDesc = target.asObject()->getOwnProperty(state, propertyName);
|
||||
|
|
@ -878,13 +923,12 @@ ObjectGetResult ProxyObject::get(ExecutionState& state, const ObjectPropertyName
|
|||
// https://www.ecma-international.org/ecma-262/6.0/index.html#sec-proxy-object-internal-methods-and-internal-slots-set-p-v-receiver
|
||||
bool ProxyObject::set(ExecutionState& state, const ObjectPropertyName& propertyName, const Value& v, const Value& receiver)
|
||||
{
|
||||
CHECK_STACK_OVERFLOW(state);
|
||||
//CHECK_STACK_OVERFLOW(state);
|
||||
|
||||
auto strings = &state.context()->staticStrings();
|
||||
// 3. If handler is null, throw a TypeError exception.
|
||||
if (this->handler() == nullptr) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString, "%s: Proxy Type Error.");
|
||||
return false;
|
||||
THROW_BUILTIN_ERROR_RETURN_ZERO(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString, "%s: Proxy Type Error.");
|
||||
}
|
||||
|
||||
// 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
|
||||
|
|
@ -900,6 +944,7 @@ bool ProxyObject::set(ExecutionState& state, const ObjectPropertyName& propertyN
|
|||
// 7. ReturnIfAbrupt(trap).
|
||||
Value trap;
|
||||
trap = Object::getMethod(state, handler, ObjectPropertyName(state, strings->set.string()));
|
||||
RETURN_ZERO_IF_PENDING_EXCEPTION
|
||||
|
||||
// 8. If trap is undefined, then
|
||||
// a. Return target.[[Set]](P, V, Receiver).
|
||||
|
|
@ -909,9 +954,10 @@ bool ProxyObject::set(ExecutionState& state, const ObjectPropertyName& propertyN
|
|||
|
||||
// 9. Let booleanTrapResult be ToBoolean(Call(trap, handler, «target, P, V, Receiver»)).
|
||||
// 10. ReturnIfAbrupt(booleanTrapResult).
|
||||
bool booleanTrapResult;
|
||||
Value arguments[] = { target, propertyName.toPropertyKeyValue(), v, receiver };
|
||||
booleanTrapResult = Object::call(state, trap, handler, 4, arguments).toBoolean(state);
|
||||
Value trapResult = Object::call(state, trap, handler, 4, arguments);
|
||||
RETURN_ZERO_IF_PENDING_EXCEPTION
|
||||
bool booleanTrapResult = trapResult.toBoolean(state);
|
||||
|
||||
// 11. If booleanTrapResult is false, return false.
|
||||
if (!booleanTrapResult) {
|
||||
|
|
@ -927,16 +973,14 @@ bool ProxyObject::set(ExecutionState& state, const ObjectPropertyName& propertyN
|
|||
if (targetDesc.isDataProperty() && !targetDesc.isConfigurable() && !targetDesc.isWritable()) {
|
||||
// i. If SameValue(V, targetDesc.[[Value]]) is false, throw a TypeError exception.
|
||||
if (v != targetDesc.value(state, target)) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString, "%s: Proxy Type Error.");
|
||||
return false;
|
||||
THROW_BUILTIN_ERROR_RETURN_ZERO(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString, "%s: Proxy Type Error.");
|
||||
}
|
||||
}
|
||||
// b. TODO If IsAccessorDescriptor(targetDesc) and targetDesc.[[Configurable]] is false, then
|
||||
if (!targetDesc.isDataProperty() && !targetDesc.isConfigurable()) {
|
||||
// i. If targetDesc.[[Set]] is undefined, throw a TypeError exception.
|
||||
if ((!targetDesc.jsGetterSetter()->hasSetter() || targetDesc.jsGetterSetter()->setter().isUndefined())) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString, "%s: Proxy Type Error.");
|
||||
return false;
|
||||
THROW_BUILTIN_ERROR_RETURN_ZERO(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString, "%s: Proxy Type Error.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -949,14 +993,13 @@ bool ProxyObject::set(ExecutionState& state, const ObjectPropertyName& propertyN
|
|||
Value ProxyObject::call(ExecutionState& state, const Value& receiver, const size_t argc, Value* argv)
|
||||
{
|
||||
if (UNLIKELY(!m_isCallable)) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::NOT_Callable);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::NOT_Callable);
|
||||
}
|
||||
|
||||
auto strings = &state.context()->staticStrings();
|
||||
// 2. If handler is null, throw a TypeError exception.
|
||||
if (this->handler() == nullptr) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString, "%s: Proxy handler should not be null.");
|
||||
return Value();
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString, "%s: Proxy handler should not be null.");
|
||||
}
|
||||
|
||||
// 1. Let handler be the value of the [[ProxyHandler]] internal slot of O.
|
||||
|
|
@ -972,6 +1015,7 @@ Value ProxyObject::call(ExecutionState& state, const Value& receiver, const size
|
|||
// 6. ReturnIfAbrupt(trap).
|
||||
Value trap;
|
||||
trap = Object::getMethod(state, handler, ObjectPropertyName(state, strings->apply.string()));
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// 7. If trap is undefined, then
|
||||
// a. Return Call(target, thisArgument, argumentsList).
|
||||
|
|
@ -993,8 +1037,7 @@ Value ProxyObject::construct(ExecutionState& state, const size_t argc, Value* ar
|
|||
auto strings = &state.context()->staticStrings();
|
||||
// 2. If handler is null, throw a TypeError exception.
|
||||
if (this->handler() == nullptr) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString, "%s: Proxy handler should not be null.");
|
||||
return Value();
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString, "%s: Proxy handler should not be null.");
|
||||
}
|
||||
|
||||
// 1. Let handler be the value of the [[ProxyHandler]] internal slot of O.
|
||||
|
|
@ -1010,13 +1053,14 @@ Value ProxyObject::construct(ExecutionState& state, const size_t argc, Value* ar
|
|||
// 6. ReturnIfAbrupt(trap).
|
||||
Value trap;
|
||||
trap = Object::getMethod(state, handler, ObjectPropertyName(state, strings->construct.string()));
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// 7. If trap is undefined, then
|
||||
// a. Assert: target has a [[Construct]] internal method.
|
||||
// b. Return Construct(target, argumentsList, newTarget).
|
||||
if (trap.isUndefined()) {
|
||||
ASSERT(target.isConstructor());
|
||||
return Object::construct(state, target, argc, argv, newTarget).toObject(state);
|
||||
return Object::construct(state, target, argc, argv, newTarget);
|
||||
}
|
||||
|
||||
// 8. Let argArray be CreateArrayFromList(argumentsList).
|
||||
|
|
@ -1025,11 +1069,11 @@ Value ProxyObject::construct(ExecutionState& state, const size_t argc, Value* ar
|
|||
// 9. Let newObj be Call(trap, handler, «target, argArray, newTarget »).
|
||||
Value arguments[] = { target, Value(argArray), Value(newTarget) };
|
||||
Value newObj = Object::call(state, trap, handler, 3, arguments);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// 11. If Type(newObj) is not Object, throw a TypeError exception.
|
||||
if (!newObj.isObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString, "%s: The result of [[Construct]] must be an Object.");
|
||||
return Value();
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, strings->Proxy.string(), false, String::emptyString, "%s: The result of [[Construct]] must be an Object.");
|
||||
}
|
||||
|
||||
// 12. Return newObj.
|
||||
|
|
|
|||
|
|
@ -150,13 +150,15 @@ void RegExpObject::internalInit(ExecutionState& state, String* source, Option op
|
|||
m_source = escapeSlashInPattern(m_source);
|
||||
|
||||
auto entry = getCacheEntryAndCompileIfNeeded(state, m_source, this->option());
|
||||
RETURN_IF_PENDING_EXCEPTION
|
||||
if (entry.m_yarrError) {
|
||||
m_source = previousSource;
|
||||
setOptionValueForGC(previousOptions);
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::SyntaxError, entry.m_yarrError);
|
||||
THROW_BUILTIN_ERROR_RETURN(state, ErrorCode::SyntaxError, entry.m_yarrError);
|
||||
}
|
||||
|
||||
setLastIndex(state, Value(0));
|
||||
RETURN_IF_PENDING_EXCEPTION
|
||||
m_yarrPattern = entry.m_yarrPattern;
|
||||
m_bytecodePattern = entry.m_bytecodePattern;
|
||||
}
|
||||
|
|
@ -164,7 +166,9 @@ void RegExpObject::internalInit(ExecutionState& state, String* source, Option op
|
|||
void RegExpObject::init(ExecutionState& state, String* source, String* option)
|
||||
{
|
||||
Option optionVals = parseOption(state, option);
|
||||
RETURN_IF_PENDING_EXCEPTION
|
||||
internalInit(state, source, optionVals);
|
||||
RETURN_IF_PENDING_EXCEPTION
|
||||
m_optionString = option;
|
||||
}
|
||||
|
||||
|
|
@ -204,33 +208,51 @@ RegExpObject::Option RegExpObject::parseOption(ExecutionState& state, String* op
|
|||
for (size_t i = 0; i < bufferAccessData.length; i++) {
|
||||
switch (bufferAccessData.charAt(i)) {
|
||||
case 'g':
|
||||
if (tempOption & Option::Global)
|
||||
if (tempOption & Option::Global) {
|
||||
// Return Exception Done!
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::SyntaxError, "RegExp has multiple 'g' flags");
|
||||
break;
|
||||
}
|
||||
tempOption = (Option)(tempOption | Option::Global);
|
||||
break;
|
||||
case 'i':
|
||||
if (tempOption & Option::IgnoreCase)
|
||||
if (tempOption & Option::IgnoreCase) {
|
||||
// Return Exception Done!
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::SyntaxError, "RegExp has multiple 'i' flags");
|
||||
break;
|
||||
}
|
||||
tempOption = (Option)(tempOption | Option::IgnoreCase);
|
||||
break;
|
||||
case 'm':
|
||||
if (tempOption & Option::MultiLine)
|
||||
if (tempOption & Option::MultiLine) {
|
||||
// Return Exception Done!
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::SyntaxError, "RegExp has multiple 'm' flags");
|
||||
break;
|
||||
}
|
||||
tempOption = (Option)(tempOption | Option::MultiLine);
|
||||
break;
|
||||
case 'u':
|
||||
if (tempOption & Option::Unicode)
|
||||
if (tempOption & Option::Unicode) {
|
||||
// Return Exception Done!
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::SyntaxError, "RegExp has multiple 'u' flags");
|
||||
break;
|
||||
}
|
||||
tempOption = (Option)(tempOption | Option::Unicode);
|
||||
break;
|
||||
case 'y':
|
||||
if (tempOption & Option::Sticky)
|
||||
if (tempOption & Option::Sticky) {
|
||||
// Return Exception Done!
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::SyntaxError, "RegExp has multiple 'y' flags");
|
||||
break;
|
||||
}
|
||||
tempOption = (Option)(tempOption | Option::Sticky);
|
||||
break;
|
||||
case 's':
|
||||
if (tempOption & Option::DotAll)
|
||||
if (tempOption & Option::DotAll) {
|
||||
// Return Exception Done!
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::SyntaxError, "RegExp has multiple 's' flags");
|
||||
break;
|
||||
}
|
||||
tempOption = (Option)(tempOption | Option::DotAll);
|
||||
break;
|
||||
default:
|
||||
|
|
@ -266,7 +288,10 @@ RegExpObject::RegExpCacheEntry& RegExpObject::getCacheEntryAndCompileIfNeeded(Ex
|
|||
yarrPattern = JSC::Yarr::YarrPattern::createYarrPattern(source, (JSC::Yarr::RegExpFlags)option, errorCode);
|
||||
yarrError = JSC::Yarr::errorMessage(errorCode);
|
||||
} catch (const std::bad_alloc& e) {
|
||||
// Return Exception Done!
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "got too complicated RegExp pattern to process");
|
||||
auto iter = cache->insert(std::make_pair(RegExpCacheKey(source, option), RegExpCacheEntry())).first;
|
||||
return iter.value();
|
||||
}
|
||||
auto iter = cache->insert(std::make_pair(RegExpCacheKey(source, option), RegExpCacheEntry(yarrError, yarrPattern))).first;
|
||||
return iter.value();
|
||||
|
|
@ -291,6 +316,7 @@ bool RegExpObject::match(ExecutionState& state, String* str, RegexMatchResult& m
|
|||
|
||||
if (!m_bytecodePattern) {
|
||||
RegExpCacheEntry& entry = getCacheEntryAndCompileIfNeeded(state, m_source, option());
|
||||
RETURN_ZERO_IF_PENDING_EXCEPTION
|
||||
if (entry.m_yarrError) {
|
||||
matchResult.m_subPatternNum = 0;
|
||||
return false;
|
||||
|
|
@ -356,6 +382,7 @@ bool RegExpObject::match(ExecutionState& state, String* str, RegexMatchResult& m
|
|||
// outputBuf[1] should be set to lastIndex
|
||||
if (isGlobal || isSticky) {
|
||||
setLastIndex(state, Value(outputBuf[1]));
|
||||
RETURN_ZERO_IF_PENDING_EXCEPTION
|
||||
}
|
||||
if (!lastParenInvalid && subPatternNum) {
|
||||
legacyFeatures.lastParen = StringView(str, outputBuf[maxMatchedIndex * 2], outputBuf[maxMatchedIndex * 2 + 1]);
|
||||
|
|
@ -402,6 +429,7 @@ bool RegExpObject::match(ExecutionState& state, String* str, RegexMatchResult& m
|
|||
|
||||
if (!gotResult && ((option() & (RegExpObject::Option::Global | RegExpObject::Option::Sticky)))) {
|
||||
setLastIndex(state, Value(0));
|
||||
RETURN_ZERO_IF_PENDING_EXCEPTION
|
||||
}
|
||||
|
||||
return matchResult.m_matchResults.size();
|
||||
|
|
@ -417,11 +445,12 @@ void RegExpObject::createRegexMatchResult(ExecutionState& state, String* str, Re
|
|||
do {
|
||||
const size_t maximumReasonableMatchSize = 1000000000;
|
||||
if (len > maximumReasonableMatchSize) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, "Maximum Reasonable match size exceeded.");
|
||||
THROW_BUILTIN_ERROR_RETURN(state, ErrorCode::RangeError, "Maximum Reasonable match size exceeded.");
|
||||
}
|
||||
|
||||
if (lastIndex().toIndex(state) == previousLastIndex) {
|
||||
setLastIndex(state, Value(previousLastIndex++));
|
||||
RETURN_IF_PENDING_EXCEPTION
|
||||
} else {
|
||||
previousLastIndex = lastIndex().toIndex(state);
|
||||
}
|
||||
|
|
@ -485,6 +514,7 @@ ArrayObject* RegExpObject::createRegExpMatchedArray(ExecutionState& state, const
|
|||
state.context()->regexpLegacyFeatures().invalidate();
|
||||
}
|
||||
}
|
||||
ASSERT(!state.hasPendingException());
|
||||
return arr;
|
||||
}
|
||||
|
||||
|
|
@ -502,6 +532,7 @@ void RegExpObject::pushBackToRegExpMatchedArray(ExecutionState& state, ArrayObje
|
|||
}
|
||||
if (index == limit)
|
||||
return;
|
||||
RETURN_IF_PENDING_EXCEPTION
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ String* RopeString::createRopeString(String* lstr, String* rstr, ExecutionState*
|
|||
}
|
||||
|
||||
if (state && UNLIKELY((llen + rlen) > STRING_MAXIMUM_LENGTH)) {
|
||||
ErrorObject::throwBuiltinError(*state, ErrorCode::RangeError, ErrorObject::Messages::String_InvalidStringLength);
|
||||
THROW_BUILTIN_ERROR_RETURN_NULL(*state, ErrorCode::RangeError, ErrorObject::Messages::String_InvalidStringLength);
|
||||
}
|
||||
|
||||
bool l8bit = lstr->has8BitContent();
|
||||
|
|
|
|||
|
|
@ -106,23 +106,22 @@ void SandBox::processCatch(const Value& error, SandBoxResult& result)
|
|||
SandBox::SandBoxResult SandBox::run(Value (*scriptRunner)(ExecutionState&, void*), void* data)
|
||||
{
|
||||
SandBox::SandBoxResult result;
|
||||
try {
|
||||
ExecutionState state(m_context);
|
||||
result.result = scriptRunner(state, data);
|
||||
} catch (const Value& err) {
|
||||
processCatch(err, result);
|
||||
ExecutionState state(m_context);
|
||||
result.result = scriptRunner(state, data);
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
ASSERT(result.result.isException());
|
||||
processCatch(state.detachPendingException(), result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
SandBox::SandBoxResult SandBox::run(const std::function<Value()>& scriptRunner)
|
||||
SandBox::SandBoxResult SandBox::run(const std::function<Value()>& scriptRunner, ExecutionState& state)
|
||||
{
|
||||
SandBox::SandBoxResult result;
|
||||
|
||||
try {
|
||||
result.result = scriptRunner();
|
||||
} catch (const Value& err) {
|
||||
processCatch(err, result);
|
||||
result.result = scriptRunner();
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
ASSERT(result.result.isException());
|
||||
processCatch(state.detachPendingException(), result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
@ -297,7 +296,8 @@ void SandBox::throwException(ExecutionState& state, const Value& exception)
|
|||
// We MUST save thrown exception Value.
|
||||
// because bdwgc cannot track `thrown value`(may turned off by GC_DONT_REGISTER_MAIN_STATIC_DATA)
|
||||
m_exception = exception;
|
||||
throw exception;
|
||||
// pending throw an exception
|
||||
// throw exception;
|
||||
}
|
||||
|
||||
void SandBox::rethrowPreviouslyCaughtException(ExecutionState& state, Value exception, StackTraceDataVector&& stackTraceDataVector)
|
||||
|
|
@ -309,13 +309,14 @@ void SandBox::rethrowPreviouslyCaughtException(ExecutionState& state, Value exce
|
|||
// We MUST save thrown exception Value.
|
||||
// because bdwgc cannot track `thrown value`(may turned off by GC_DONT_REGISTER_MAIN_STATIC_DATA)
|
||||
m_exception = exception;
|
||||
throw exception;
|
||||
// pending throw an exception
|
||||
// throw exception;
|
||||
}
|
||||
|
||||
static Value builtinErrorObjectStackInfo(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
if (!(LIKELY(thisValue.isPointerValue() && thisValue.asPointerValue()->isErrorObject()))) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "get Error.prototype.stack called on incompatible receiver");
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "get Error.prototype.stack called on incompatible receiver");
|
||||
}
|
||||
|
||||
ErrorObject* obj = thisValue.asObject()->asErrorObject();
|
||||
|
|
@ -353,20 +354,18 @@ void ErrorObject::StackTraceData::buildStackTrace(Context* context, StringBuilde
|
|||
{
|
||||
if (exception.isObject()) {
|
||||
ExecutionState state(context);
|
||||
try {
|
||||
auto getResult = exception.asObject()->get(state, state.context()->staticStrings().name);
|
||||
if (getResult.hasValue()) {
|
||||
builder.appendString(getResult.value(state, exception.asObject()).toString(state));
|
||||
builder.appendString(": ");
|
||||
}
|
||||
getResult = exception.asObject()->get(state, state.context()->staticStrings().message);
|
||||
if (getResult.hasValue()) {
|
||||
builder.appendString(getResult.value(state, exception.asObject()).toString(state));
|
||||
builder.appendChar('\n');
|
||||
}
|
||||
} catch (const Value& v) {
|
||||
// ignore exception
|
||||
auto getResult = exception.asObject()->get(state, state.context()->staticStrings().name);
|
||||
if (getResult.hasValue()) {
|
||||
builder.appendString(getResult.value(state, exception.asObject()).toString(state));
|
||||
builder.appendString(": ");
|
||||
}
|
||||
getResult = exception.asObject()->get(state, state.context()->staticStrings().message);
|
||||
if (getResult.hasValue()) {
|
||||
builder.appendString(getResult.value(state, exception.asObject()).toString(state));
|
||||
builder.appendChar('\n');
|
||||
}
|
||||
// ignore exception
|
||||
ASSERT(!state.hasPendingException());
|
||||
}
|
||||
|
||||
ByteCodeLOCDataMap locMap;
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
SandBoxResult run(const std::function<Value()>& scriptRunner); // for capsule script executing with try-catch
|
||||
SandBoxResult run(const std::function<Value()>& scriptRunner, ExecutionState& state); // for capsule script executing with try-catch
|
||||
SandBoxResult run(Value (*runner)(ExecutionState&, void*), void* data);
|
||||
|
||||
static bool createStackTrace(StackTraceDataVector& stackTraceDataVector, ExecutionState& state, bool stopAtPause = false);
|
||||
|
|
@ -98,6 +98,11 @@ public:
|
|||
return m_context;
|
||||
}
|
||||
|
||||
Value exception()
|
||||
{
|
||||
return m_exception;
|
||||
}
|
||||
|
||||
protected:
|
||||
void processCatch(const Value& error, SandBoxResult& result);
|
||||
void fillStackDataIntoErrorObject(const Value& e);
|
||||
|
|
|
|||
|
|
@ -41,8 +41,8 @@ Value ScriptArrowFunctionObject::construct(ExecutionState& state, const size_t a
|
|||
{
|
||||
ExecutionState newState(m_codeBlock->context(), &state,
|
||||
static_cast<LexicalEnvironment*>(nullptr), argc, argv, m_codeBlock->asInterpretedCodeBlock()->isStrict());
|
||||
ErrorObject::throwBuiltinError(newState, ErrorCode::TypeError, "Arrow function cannot be invoked with 'new'");
|
||||
ASSERT_NOT_REACHED();
|
||||
return Value();
|
||||
// set exception for upper state
|
||||
state.setPendingException();
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(newState, ErrorCode::TypeError, "Arrow function cannot be invoked with 'new'");
|
||||
}
|
||||
} // namespace Escargot
|
||||
|
|
|
|||
|
|
@ -79,9 +79,9 @@ Value ScriptAsyncFunctionObject::construct(ExecutionState& state, const size_t a
|
|||
{
|
||||
ExecutionState newState(m_codeBlock->context(), &state,
|
||||
static_cast<LexicalEnvironment*>(nullptr), argc, argv, m_codeBlock->asInterpretedCodeBlock()->isStrict());
|
||||
ErrorObject::throwBuiltinError(newState, ErrorCode::TypeError, "Async function cannot be invoked with 'new'");
|
||||
ASSERT_NOT_REACHED();
|
||||
return Value();
|
||||
// set exception for upper state
|
||||
state.setPendingException();
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(newState, ErrorCode::TypeError, "Async function cannot be invoked with 'new'");
|
||||
}
|
||||
|
||||
class ScriptAsyncFunctionHelperFunctionObject : public NativeFunctionObject {
|
||||
|
|
@ -115,6 +115,7 @@ static Value awaitFulfilledFunction(ExecutionState& state, Value thisValue, size
|
|||
{
|
||||
ScriptAsyncFunctionHelperFunctionObject* self = (ScriptAsyncFunctionHelperFunctionObject*)state.resolveCallee();
|
||||
awaitFulfilledFunctions(state, self, argv[0]);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
return Value();
|
||||
}
|
||||
|
||||
|
|
@ -136,6 +137,7 @@ static Value awaitRejectedFunction(ExecutionState& state, Value thisValue, size_
|
|||
{
|
||||
ScriptAsyncFunctionHelperFunctionObject* self = (ScriptAsyncFunctionHelperFunctionObject*)state.resolveCallee();
|
||||
awaitRejectedFunctions(state, self, argv[0]);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
return Value();
|
||||
}
|
||||
|
||||
|
|
@ -144,7 +146,9 @@ PromiseObject* ScriptAsyncFunctionObject::awaitOperationBeforePause(ExecutionSta
|
|||
{
|
||||
// Let asyncContext be the running execution context.
|
||||
// Let promise be ? PromiseResolve(%Promise%, « value »).
|
||||
PromiseObject* promise = PromiseObject::promiseResolve(state, state.context()->globalObject()->promise(), awaitValue)->asPromiseObject();
|
||||
auto promiseObj = PromiseObject::promiseResolve(state, state.context()->globalObject()->promise(), awaitValue);
|
||||
RETURN_NULL_IF_PENDING_EXCEPTION
|
||||
auto promise = promiseObj->asPromiseObject();
|
||||
// Let stepsFulfilled be the algorithm steps defined in Await Fulfilled Functions.
|
||||
// Let onFulfilled be CreateBuiltinFunction(stepsFulfilled, « [[AsyncContext]] »).
|
||||
// Set onFulfilled.[[AsyncContext]] to asyncContext.
|
||||
|
|
|
|||
|
|
@ -77,8 +77,8 @@ Value ScriptAsyncGeneratorFunctionObject::construct(ExecutionState& state, const
|
|||
{
|
||||
ExecutionState newState(m_codeBlock->context(), &state,
|
||||
static_cast<LexicalEnvironment*>(nullptr), argc, argv, m_codeBlock->asInterpretedCodeBlock()->isStrict());
|
||||
ErrorObject::throwBuiltinError(newState, ErrorCode::TypeError, "AsyncGenerator cannot be invoked with 'new'");
|
||||
ASSERT_NOT_REACHED();
|
||||
return Value();
|
||||
// set exception for upper state
|
||||
state.setPendingException();
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(newState, ErrorCode::TypeError, "AsyncGenerator cannot be invoked with 'new'");
|
||||
}
|
||||
} // namespace Escargot
|
||||
|
|
|
|||
|
|
@ -61,21 +61,24 @@ ScriptClassConstructorFunctionObject::ScriptClassConstructorFunctionObject(Execu
|
|||
Value ScriptClassConstructorFunctionObject::call(ExecutionState& state, const Value& thisValue, const size_t argc, Value* argv)
|
||||
{
|
||||
ExecutionState newState(m_codeBlock->context(), &state, static_cast<LexicalEnvironment*>(nullptr), argc, argv, m_codeBlock->asInterpretedCodeBlock()->isStrict());
|
||||
ErrorObject::throwBuiltinError(newState, ErrorCode::TypeError, "Class constructor cannot be invoked without 'new'");
|
||||
return Value();
|
||||
// set exception for upper state
|
||||
state.setPendingException();
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(newState, ErrorCode::TypeError, "Class constructor cannot be invoked without 'new'");
|
||||
}
|
||||
|
||||
class ScriptClassConstructorFunctionObjectThisValueBinder {
|
||||
public:
|
||||
Value operator()(ExecutionState& callerState, ExecutionState& calleeState, ScriptClassConstructorFunctionObject* self, const Value& thisArgument, bool isStrict)
|
||||
Value operator()(ExecutionState& callerState, ExecutionState& state, ScriptClassConstructorFunctionObject* self, const Value& thisArgument, bool isStrict)
|
||||
{
|
||||
// Let envRec be localEnv’s EnvironmentRecord.
|
||||
// Assert: The next step never returns an abrupt completion because envRec.[[thisBindingStatus]] is not "uninitialized".
|
||||
// Return envRec.BindThisValue(thisValue).
|
||||
if (self->constructorKind() == ScriptFunctionObject::ConstructorKind::Base) {
|
||||
FunctionEnvironmentRecord* r = calleeState.lexicalEnvironment()->record()->asDeclarativeEnvironmentRecord()->asFunctionEnvironmentRecord();
|
||||
r->bindThisValue(calleeState, thisArgument);
|
||||
r->functionObject()->asScriptClassConstructorFunctionObject()->initInstanceFieldMembers(calleeState, thisArgument.asObject());
|
||||
FunctionEnvironmentRecord* r = state.lexicalEnvironment()->record()->asDeclarativeEnvironmentRecord()->asFunctionEnvironmentRecord();
|
||||
r->bindThisValue(state, thisArgument);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
r->functionObject()->asScriptClassConstructorFunctionObject()->initInstanceFieldMembers(state, thisArgument.asObject());
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
}
|
||||
|
||||
return thisArgument;
|
||||
|
|
@ -96,6 +99,10 @@ public:
|
|||
{
|
||||
// Let result be OrdinaryCallEvaluateBody(F, argumentsList).
|
||||
const Value& result = interpreterReturnValue;
|
||||
if (UNLIKELY(result.isException())) {
|
||||
return interpreterReturnValue;
|
||||
}
|
||||
|
||||
// If result.[[type]] is return, then
|
||||
// If Type(result.[[value]]) is Object, return NormalCompletion(result.[[value]]).
|
||||
if (result.isObject()) {
|
||||
|
|
@ -107,7 +114,7 @@ public:
|
|||
}
|
||||
// If result.[[value]] is not undefined, throw a TypeError exception.
|
||||
if (!result.isUndefined()) {
|
||||
ErrorObject::throwBuiltinError(callerState, ErrorCode::TypeError, ErrorObject::Messages::InvalidDerivedConstructorReturnValue);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(callerState, ErrorCode::TypeError, ErrorObject::Messages::InvalidDerivedConstructorReturnValue);
|
||||
}
|
||||
// Else, ReturnIfAbrupt(result).
|
||||
// Return envRec.GetThisBinding().
|
||||
|
|
@ -129,6 +136,7 @@ Value ScriptClassConstructorFunctionObject::construct(ExecutionState& state, con
|
|||
Object* proto = Object::getPrototypeFromConstructor(state, newTarget, [](ExecutionState& state, Context* constructorRealm) -> Object* {
|
||||
return constructorRealm->globalObject()->objectPrototype();
|
||||
});
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Set the [[Prototype]] internal slot of obj to proto.
|
||||
thisArgument = new Object(state, proto);
|
||||
// ReturnIfAbrupt(thisArgument).
|
||||
|
|
@ -171,6 +179,7 @@ void ScriptClassConstructorFunctionObject::initInstanceFieldMembers(ExecutionSta
|
|||
} else {
|
||||
ASSERT(kind == ScriptClassConstructorFunctionObject::NotPrivate || kind == ScriptClassConstructorFunctionObject::PrivateFieldValue);
|
||||
}
|
||||
RETURN_IF_PENDING_EXCEPTION
|
||||
}
|
||||
|
||||
// phase 2
|
||||
|
|
@ -184,6 +193,7 @@ void ScriptClassConstructorFunctionObject::initInstanceFieldMembers(ExecutionSta
|
|||
case ScriptClassConstructorFunctionObject::PrivateFieldValue:
|
||||
if (!value.isUndefined()) {
|
||||
value = value.asPointerValue()->asScriptVirtualArrowFunctionObject()->call(state, Value(instance), homeObject);
|
||||
RETURN_IF_PENDING_EXCEPTION
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
|
@ -192,11 +202,13 @@ void ScriptClassConstructorFunctionObject::initInstanceFieldMembers(ExecutionSta
|
|||
|
||||
if (kind == ScriptClassConstructorFunctionObject::NotPrivate) {
|
||||
instance->defineOwnPropertyThrowsException(state, ObjectPropertyName(state, name), ObjectPropertyDescriptor(value, ObjectPropertyDescriptor::AllPresent));
|
||||
ASSERT(!state.hasPendingException());
|
||||
} else if (kind == ScriptClassConstructorFunctionObject::PrivateFieldValue) {
|
||||
instance->addPrivateField(state, privateContextObject, AtomicString(state, name.asString()), value);
|
||||
} else {
|
||||
ASSERT(kind == ScriptClassConstructorFunctionObject::PrivateFieldMethod || kind == ScriptClassConstructorFunctionObject::PrivateFieldGetter || kind == ScriptClassConstructorFunctionObject::PrivateFieldSetter);
|
||||
}
|
||||
RETURN_IF_PENDING_EXCEPTION
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -132,6 +132,9 @@ public:
|
|||
{
|
||||
// Let result be OrdinaryCallEvaluateBody(F, argumentsList).
|
||||
const Value& result = interpreterReturnValue;
|
||||
if (UNLIKELY(result.isException())) {
|
||||
return result;
|
||||
}
|
||||
// If result.[[type]] is return, then
|
||||
// If Type(result.[[value]]) is Object, return NormalCompletion(result.[[value]]).
|
||||
if (result.isObject()) {
|
||||
|
|
@ -163,6 +166,7 @@ Value ScriptFunctionObject::construct(ExecutionState& state, const size_t argc,
|
|||
Object* proto = Object::getPrototypeFromConstructor(state, newTarget, [](ExecutionState& state, Context* constructorRealm) -> Object* {
|
||||
return constructorRealm->globalObject()->objectPrototype();
|
||||
});
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// Set the [[Prototype]] internal slot of obj to proto.
|
||||
Object* thisArgument = new Object(state, proto);
|
||||
|
||||
|
|
@ -184,9 +188,11 @@ void ScriptFunctionObject::generateArgumentsObject(ExecutionState& state, size_t
|
|||
auto result = environmentRecordWillArgumentsObjectBeLocatedIn->hasBinding(state, arguments);
|
||||
if (UNLIKELY(result.m_index == SIZE_MAX)) {
|
||||
environmentRecordWillArgumentsObjectBeLocatedIn->createBinding(state, arguments, false, true);
|
||||
ASSERT(!state.hasPendingException());
|
||||
result = environmentRecordWillArgumentsObjectBeLocatedIn->hasBinding(state, arguments);
|
||||
}
|
||||
environmentRecordWillArgumentsObjectBeLocatedIn->initializeBinding(state, arguments, newArgumentsObject);
|
||||
ASSERT(!state.hasPendingException());
|
||||
} else {
|
||||
const InterpretedCodeBlock::IdentifierInfoVector& v = interpretedCodeBlock()->identifierInfos();
|
||||
for (size_t i = 0; i < v.size(); i++) {
|
||||
|
|
@ -195,6 +201,7 @@ void ScriptFunctionObject::generateArgumentsObject(ExecutionState& state, size_t
|
|||
stackStorage[v[i].m_indexForIndexedStorage] = newArgumentsObject;
|
||||
} else {
|
||||
environmentRecordWillArgumentsObjectBeLocatedIn->setHeapValueByIndex(state, v[i].m_indexForIndexedStorage, newArgumentsObject);
|
||||
ASSERT(!state.hasPendingException());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,8 +77,8 @@ Value ScriptGeneratorFunctionObject::construct(ExecutionState& state, const size
|
|||
{
|
||||
ExecutionState newState(m_codeBlock->context(), &state,
|
||||
static_cast<LexicalEnvironment*>(nullptr), argc, argv, m_codeBlock->asInterpretedCodeBlock()->isStrict());
|
||||
ErrorObject::throwBuiltinError(newState, ErrorCode::TypeError, "Generator cannot be invoked with 'new'");
|
||||
ASSERT_NOT_REACHED();
|
||||
return Value();
|
||||
// set exception for upper state
|
||||
state.setPendingException();
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(newState, ErrorCode::TypeError, "Generator cannot be invoked with 'new'");
|
||||
}
|
||||
} // namespace Escargot
|
||||
|
|
|
|||
|
|
@ -96,13 +96,17 @@ protected:
|
|||
}
|
||||
}
|
||||
|
||||
if (shouldClearStack) {
|
||||
const Value returnValue = Interpreter::interpret(&newState, blk, programStart, registerFile);
|
||||
clearStack<512>();
|
||||
return returnValue;
|
||||
} else {
|
||||
return Interpreter::interpret(&newState, blk, programStart, registerFile);
|
||||
const Value returnValue = Interpreter::interpret(&newState, blk, programStart, registerFile);
|
||||
// check Exception
|
||||
if (UNLIKELY(newState.hasPendingException())) {
|
||||
ASSERT(returnValue.isException());
|
||||
state.setPendingException();
|
||||
}
|
||||
|
||||
if (shouldClearStack) {
|
||||
clearStack<512>();
|
||||
}
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
virtual Value construct(ExecutionState& state, const size_t argc, Value* argv, Object* newTarget) override
|
||||
|
|
@ -119,6 +123,7 @@ protected:
|
|||
Object* proto = Object::getPrototypeFromConstructor(state, newTarget, [](ExecutionState& state, Context* constructorRealm) -> Object* {
|
||||
return constructorRealm->globalObject()->objectPrototype();
|
||||
});
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
|
||||
// Set the [[Prototype]] internal slot of obj to proto.
|
||||
Object* thisArgument = new Object(state, proto);
|
||||
|
|
@ -162,6 +167,11 @@ protected:
|
|||
record.setNewTarget(newTarget);
|
||||
|
||||
const Value returnValue = Interpreter::interpret(&newState, blk, reinterpret_cast<const size_t>(blk->m_code.data()), registerFile);
|
||||
// check Exception
|
||||
if (UNLIKELY(newState.hasPendingException())) {
|
||||
ASSERT(returnValue.isException());
|
||||
state.setPendingException();
|
||||
}
|
||||
if (shouldClearStack) {
|
||||
clearStack<512>();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,17 +53,17 @@ Value ScriptVirtualArrowFunctionObject::call(ExecutionState& state, const Value&
|
|||
{
|
||||
ExecutionState newState(m_codeBlock->context(), &state,
|
||||
static_cast<LexicalEnvironment*>(nullptr), argc, argv, m_codeBlock->asInterpretedCodeBlock()->isStrict());
|
||||
ErrorObject::throwBuiltinError(newState, ErrorCode::TypeError, "This function cannot be invoked");
|
||||
ASSERT_NOT_REACHED();
|
||||
return Value();
|
||||
// set exception for upper state
|
||||
state.setPendingException();
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(newState, ErrorCode::TypeError, "This function cannot be invoked");
|
||||
}
|
||||
|
||||
Value ScriptVirtualArrowFunctionObject::construct(ExecutionState& state, const size_t argc, Value* argv, Object* newTarget)
|
||||
{
|
||||
ExecutionState newState(m_codeBlock->context(), &state,
|
||||
static_cast<LexicalEnvironment*>(nullptr), argc, argv, m_codeBlock->asInterpretedCodeBlock()->isStrict());
|
||||
ErrorObject::throwBuiltinError(newState, ErrorCode::TypeError, "This function cannot be invoked");
|
||||
ASSERT_NOT_REACHED();
|
||||
return Value();
|
||||
// set exception for upper state
|
||||
state.setPendingException();
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(newState, ErrorCode::TypeError, "This function cannot be invoked");
|
||||
}
|
||||
} // namespace Escargot
|
||||
|
|
|
|||
|
|
@ -88,16 +88,17 @@ SharedArrayBufferObject* SharedArrayBufferObject::allocateSharedArrayBuffer(Exec
|
|||
Object* proto = Object::getPrototypeFromConstructor(state, constructor, [](ExecutionState& state, Context* constructorRealm) -> Object* {
|
||||
return constructorRealm->globalObject()->sharedArrayBufferPrototype();
|
||||
});
|
||||
RETURN_NULL_IF_PENDING_EXCEPTION
|
||||
|
||||
if (UNLIKELY(byteLength >= ArrayBuffer::maxArrayBufferSize)) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, state.context()->staticStrings().SharedArrayBuffer.string(), false, String::emptyString, ErrorObject::Messages::GlobalObject_InvalidArrayBufferSize);
|
||||
THROW_BUILTIN_ERROR_RETURN_NULL(state, ErrorCode::RangeError, state.context()->staticStrings().SharedArrayBuffer.string(), false, String::emptyString, ErrorObject::Messages::GlobalObject_InvalidArrayBufferSize);
|
||||
}
|
||||
|
||||
if (UNLIKELY(maxByteLength.hasValue())) {
|
||||
ASSERT(byteLength <= maxByteLength.value());
|
||||
uint64_t maxLength = maxByteLength.value();
|
||||
if (UNLIKELY(maxLength >= ArrayBuffer::maxArrayBufferSize)) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, state.context()->staticStrings().SharedArrayBuffer.string(), false, String::emptyString, ErrorObject::Messages::GlobalObject_InvalidArrayBufferSize);
|
||||
THROW_BUILTIN_ERROR_RETURN_NULL(state, ErrorCode::RangeError, state.context()->staticStrings().SharedArrayBuffer.string(), false, String::emptyString, ErrorObject::Messages::GlobalObject_InvalidArrayBufferSize);
|
||||
}
|
||||
|
||||
return new SharedArrayBufferObject(state, proto, byteLength, maxLength);
|
||||
|
|
|
|||
|
|
@ -33,7 +33,8 @@ String* StringBuilderBase::finalizeBase(StringBuilderPiece* piecesInlineStorage,
|
|||
|
||||
|
||||
if (state && UNLIKELY(m_contentLength > STRING_MAXIMUM_LENGTH)) {
|
||||
ErrorObject::throwBuiltinError(*state, ErrorCode::RangeError, ErrorObject::Messages::String_InvalidStringLength);
|
||||
RELEASE_ASSERT_NOT_REACHED();
|
||||
//ErrorObject::throwBuiltinError(*state, ErrorCode::RangeError, ErrorObject::Messages::String_InvalidStringLength);
|
||||
}
|
||||
|
||||
if (m_has8BitContent) {
|
||||
|
|
|
|||
|
|
@ -190,7 +190,9 @@ public:
|
|||
|
||||
void appendString(String* str)
|
||||
{
|
||||
appendPiece(str, 0, str->length());
|
||||
if (!!str) {
|
||||
appendPiece(str, 0, str->length());
|
||||
}
|
||||
}
|
||||
|
||||
void appendSubString(String* str, size_t s, size_t e)
|
||||
|
|
|
|||
|
|
@ -93,6 +93,7 @@ struct BigIntegralArrayAdaptor {
|
|||
static Type toNative(ExecutionState& state, const Value& val)
|
||||
{
|
||||
auto n = val.toBigInt(state);
|
||||
RETURN_ZERO_IF_PENDING_EXCEPTION
|
||||
if (std::is_same<Type, uint64_t>::value) {
|
||||
return n->toUint64();
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -139,6 +139,7 @@ void TypedArrayObject::sort(ExecutionState& state, int64_t length, const std::fu
|
|||
|
||||
for (int64_t i = 0; i < length; i++) {
|
||||
integerIndexedElementSet(state, i, tempBuffer[i]);
|
||||
ASSERT(!state.hasPendingException());
|
||||
}
|
||||
GC_FREE(tempBuffer);
|
||||
|
||||
|
|
@ -149,17 +150,18 @@ void TypedArrayObject::sort(ExecutionState& state, int64_t length, const std::fu
|
|||
ArrayBuffer* TypedArrayObject::validateTypedArray(ExecutionState& state, const Value& O)
|
||||
{
|
||||
if (!O.isObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ThisNotObject);
|
||||
THROW_BUILTIN_ERROR_RETURN_NULL(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ThisNotObject);
|
||||
}
|
||||
|
||||
Object* thisObject = O.asObject();
|
||||
if (!thisObject->isTypedArrayObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ThisNotTypedArrayObject);
|
||||
THROW_BUILTIN_ERROR_RETURN_NULL(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_ThisNotTypedArrayObject);
|
||||
}
|
||||
|
||||
auto wrapper = thisObject->asTypedArrayObject();
|
||||
ArrayBuffer* buffer = wrapper->buffer();
|
||||
buffer->throwTypeErrorIfDetached(state);
|
||||
RETURN_ZERO_IF_PENDING_EXCEPTION
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
|
@ -188,6 +190,7 @@ bool TypedArrayObject::integerIndexedElementSet(ExecutionState& state, double in
|
|||
// Otherwise, let numValue be ? ToNumber(value).
|
||||
numValue = Value(Value::DoubleToIntConvertibleTestNeeds, value.toNumber(state));
|
||||
}
|
||||
RETURN_ZERO_IF_PENDING_EXCEPTION
|
||||
|
||||
if (buffer()->isDetachedBuffer() || !Value(Value::DoubleToIntConvertibleTestNeeds, index).isInteger(state) || index == Value::MinusZeroIndex || index < 0 || index >= arrayLength()) {
|
||||
return false;
|
||||
|
|
@ -200,17 +203,19 @@ bool TypedArrayObject::integerIndexedElementSet(ExecutionState& state, double in
|
|||
}
|
||||
|
||||
#define DECLARE_TYPEDARRAY(TYPE, type, siz, nativeType) \
|
||||
TypedArrayObject* TYPE##ArrayObject::allocateTypedArray(ExecutionState& state, Object* newTarget, size_t length) \
|
||||
Value TYPE##ArrayObject::allocateTypedArray(ExecutionState& state, Object* newTarget, size_t length) \
|
||||
{ \
|
||||
ASSERT(!!newTarget); \
|
||||
Object* proto = Object::getPrototypeFromConstructor(state, newTarget, [](ExecutionState& state, Context* constructorRealm) -> Object* { \
|
||||
return constructorRealm->globalObject()->type##ArrayPrototype(); \
|
||||
}); \
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION \
|
||||
TypedArrayObject* obj = new TYPE##ArrayObject(state, proto); \
|
||||
if (length == std::numeric_limits<size_t>::max()) { \
|
||||
obj->setBuffer(nullptr, 0, 0, 0); \
|
||||
} else { \
|
||||
auto buffer = ArrayBufferObject::allocateArrayBuffer(state, state.context()->globalObject()->arrayBuffer(), length * siz); \
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION \
|
||||
obj->setBuffer(buffer, 0, length* siz, length); \
|
||||
} \
|
||||
return obj; \
|
||||
|
|
@ -260,6 +265,7 @@ bool TypedArrayObject::integerIndexedElementSet(ExecutionState& state, double in
|
|||
{ \
|
||||
typedef typename TYPE##Adaptor::Type Type; \
|
||||
Type littleEndianVal = TYPE##Adaptor::toNative(state, val); \
|
||||
RETURN_IF_PENDING_EXCEPTION \
|
||||
ASSERT(byteLength()); \
|
||||
size_t elementSize = siz; \
|
||||
ASSERT(byteindex + elementSize <= byteLength()); \
|
||||
|
|
@ -304,6 +310,7 @@ bool TypedArrayObject::integerIndexedElementSet(ExecutionState& state, double in
|
|||
if (LIKELY(property.isUInt32() && (size_t)property.asUInt32() < arrayLength() && !buffer()->isDetachedBuffer())) { \
|
||||
size_t indexedPosition = property.asUInt32() * siz; \
|
||||
setDirectValueInBuffer(state, indexedPosition, value); \
|
||||
RETURN_ZERO_IF_PENDING_EXCEPTION \
|
||||
return true; \
|
||||
} \
|
||||
return set(state, ObjectPropertyName(state, property), value, receiver); \
|
||||
|
|
|
|||
|
|
@ -100,39 +100,39 @@ protected:
|
|||
inline bool integerIndexedElementSet(ExecutionState& state, double index, const Value& value);
|
||||
};
|
||||
|
||||
#define DECLARE_TYPEDARRAY(TYPE, type, siz, nativeType) \
|
||||
class TYPE##ArrayObject : public TypedArrayObject { \
|
||||
public: \
|
||||
explicit TYPE##ArrayObject(ExecutionState& state) \
|
||||
: TYPE##ArrayObject(state, state.context()->globalObject()->type##ArrayPrototype()) \
|
||||
{ \
|
||||
} \
|
||||
explicit TYPE##ArrayObject(ExecutionState& state, Object* proto) \
|
||||
: TypedArrayObject(state, proto) \
|
||||
{ \
|
||||
} \
|
||||
static TypedArrayObject* allocateTypedArray(ExecutionState& state, Object* newTarget, size_t length = std::numeric_limits<size_t>::max()); \
|
||||
virtual TypedArrayType typedArrayType() override \
|
||||
{ \
|
||||
return TypedArrayType::TYPE; \
|
||||
} \
|
||||
virtual String* typedArrayName(ExecutionState& state) override \
|
||||
{ \
|
||||
return state.context()->staticStrings().TYPE##Array.string(); \
|
||||
} \
|
||||
virtual size_t elementSize() override \
|
||||
{ \
|
||||
return siz; \
|
||||
} \
|
||||
virtual ObjectGetResult getIndexedProperty(ExecutionState& state, const Value& property, const Value& receiver) override; \
|
||||
virtual bool setIndexedProperty(ExecutionState& state, const Value& property, const Value& value, const Value& receiver) override; \
|
||||
virtual Value getIndexedPropertyValue(ExecutionState& state, const Value& property, const Value& receiver) override; \
|
||||
\
|
||||
private: \
|
||||
template <const bool isLittleEndian = true> \
|
||||
inline Value getDirectValueFromBuffer(ExecutionState& state, size_t byteindex); \
|
||||
template <const bool isLittleEndian = true> \
|
||||
inline void setDirectValueInBuffer(ExecutionState& state, size_t byteindex, const Value& val); \
|
||||
#define DECLARE_TYPEDARRAY(TYPE, type, siz, nativeType) \
|
||||
class TYPE##ArrayObject : public TypedArrayObject { \
|
||||
public: \
|
||||
explicit TYPE##ArrayObject(ExecutionState& state) \
|
||||
: TYPE##ArrayObject(state, state.context()->globalObject()->type##ArrayPrototype()) \
|
||||
{ \
|
||||
} \
|
||||
explicit TYPE##ArrayObject(ExecutionState& state, Object* proto) \
|
||||
: TypedArrayObject(state, proto) \
|
||||
{ \
|
||||
} \
|
||||
static Value allocateTypedArray(ExecutionState& state, Object* newTarget, size_t length = std::numeric_limits<size_t>::max()); \
|
||||
virtual TypedArrayType typedArrayType() override \
|
||||
{ \
|
||||
return TypedArrayType::TYPE; \
|
||||
} \
|
||||
virtual String* typedArrayName(ExecutionState& state) override \
|
||||
{ \
|
||||
return state.context()->staticStrings().TYPE##Array.string(); \
|
||||
} \
|
||||
virtual size_t elementSize() override \
|
||||
{ \
|
||||
return siz; \
|
||||
} \
|
||||
virtual ObjectGetResult getIndexedProperty(ExecutionState& state, const Value& property, const Value& receiver) override; \
|
||||
virtual bool setIndexedProperty(ExecutionState& state, const Value& property, const Value& value, const Value& receiver) override; \
|
||||
virtual Value getIndexedPropertyValue(ExecutionState& state, const Value& property, const Value& receiver) override; \
|
||||
\
|
||||
private: \
|
||||
template <const bool isLittleEndian = true> \
|
||||
inline Value getDirectValueFromBuffer(ExecutionState& state, size_t byteindex); \
|
||||
template <const bool isLittleEndian = true> \
|
||||
inline void setDirectValueInBuffer(ExecutionState& state, size_t byteindex, const Value& val); \
|
||||
};
|
||||
|
||||
FOR_EACH_TYPEDARRAY_TYPES(DECLARE_TYPEDARRAY)
|
||||
|
|
|
|||
|
|
@ -102,7 +102,8 @@ static ObjectPropertyNativeGetterSetterData stringLengthGetterSetterData(
|
|||
Value VMInstance::regexpLastIndexNativeGetter(ExecutionState& state, Object* self, const Value& receiver, const EncodedValue& privateDataFromObjectPrivateArea)
|
||||
{
|
||||
if (!self->isRegExpObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "getter called on non-RegExp object");
|
||||
ASSERT_NOT_REACHED();
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "getter called on non-RegExp object");
|
||||
}
|
||||
return self->asRegExpObject()->lastIndex();
|
||||
}
|
||||
|
|
@ -111,6 +112,7 @@ bool VMInstance::regexpLastIndexNativeSetter(ExecutionState& state, Object* self
|
|||
{
|
||||
ASSERT(self->isRegExpObject());
|
||||
self->asRegExpObject()->setLastIndex(state, setterInputData);
|
||||
ASSERT(!state.hasPendingException());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -53,10 +53,8 @@ String* Value::toStringWithoutException(ExecutionState& ec) const
|
|||
return asString();
|
||||
}
|
||||
|
||||
String* result;
|
||||
try {
|
||||
result = toStringSlowCase(ec);
|
||||
} catch (const Value&) {
|
||||
String* result = toStringSlowCase(ec);
|
||||
if (ec.hasPendingException()) {
|
||||
result = String::fromASCII("Error while converting to string, but do not throw an exception");
|
||||
}
|
||||
return result;
|
||||
|
|
@ -66,6 +64,7 @@ Value Value::toPropertyKey(ExecutionState& state) const
|
|||
{
|
||||
// Let key be ? ToPrimitive(argument, hint String).
|
||||
Value key = toPrimitive(state, Value::PreferString);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// If Type(key) is Symbol, then
|
||||
if (key.isSymbol()) {
|
||||
// Return key.
|
||||
|
|
@ -110,12 +109,15 @@ String* Value::toStringSlowCase(ExecutionState& ec) const // $7.1.12 ToString
|
|||
else
|
||||
return ec.context()->staticStrings().stringFalse.string();
|
||||
} else if (isSymbol()) {
|
||||
ErrorObject::throwBuiltinError(ec, ErrorCode::TypeError, "Cannot convert a Symbol value to a string");
|
||||
ASSERT_NOT_REACHED();
|
||||
THROW_BUILTIN_ERROR_RETURN_NULL(ec, ErrorCode::TypeError, "Cannot convert a Symbol value to a string");
|
||||
} else if (isBigInt()) {
|
||||
return asBigInt()->toString();
|
||||
} else {
|
||||
return toPrimitive(ec, PreferString).toString(ec);
|
||||
Value prim = toPrimitive(ec, PreferString);
|
||||
if (UNLIKELY(ec.hasPendingException())) {
|
||||
return nullptr;
|
||||
}
|
||||
return prim.toString(ec);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
|
@ -134,10 +136,10 @@ Object* Value::toObjectSlowCase(ExecutionState& state) const // $7.1.13 ToObject
|
|||
} else if (isBigInt()) {
|
||||
object = new BigIntObject(state, asBigInt());
|
||||
} else if (isNull()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::NullToObject);
|
||||
THROW_BUILTIN_ERROR_RETURN_NULL(state, ErrorCode::TypeError, ErrorObject::Messages::NullToObject);
|
||||
} else {
|
||||
ASSERT(isUndefined());
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::UndefinedToObject);
|
||||
THROW_BUILTIN_ERROR_RETURN_NULL(state, ErrorCode::TypeError, ErrorObject::Messages::UndefinedToObject);
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
|
@ -147,6 +149,7 @@ BigInt* Value::toBigInt(ExecutionState& state) const
|
|||
{
|
||||
// Let prim be ? ToPrimitive(argument, hint Number).
|
||||
Value prim = toPrimitive(state, Value::PreferNumber);
|
||||
RETURN_NULL_IF_PENDING_EXCEPTION
|
||||
if (prim.isBigInt()) {
|
||||
return prim.asBigInt();
|
||||
} else if (prim.isBoolean()) {
|
||||
|
|
@ -158,18 +161,18 @@ BigInt* Value::toBigInt(ExecutionState& state) const
|
|||
auto b = BigInt::parseString(prim.asString()->trim());
|
||||
if (!b) {
|
||||
b = BigInt::parseString(prim.asString()->trim());
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::SyntaxError, "Cannot parse String as BigInt");
|
||||
THROW_BUILTIN_ERROR_RETURN_NULL(state, ErrorCode::SyntaxError, "Cannot parse String as BigInt");
|
||||
}
|
||||
return b.value();
|
||||
} else if (prim.isUndefined()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Cannot convert undefined to BigInt");
|
||||
THROW_BUILTIN_ERROR_RETURN_NULL(state, ErrorCode::TypeError, "Cannot convert undefined to BigInt");
|
||||
} else if (prim.isNull()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Cannot convert null to BigInt");
|
||||
THROW_BUILTIN_ERROR_RETURN_NULL(state, ErrorCode::TypeError, "Cannot convert null to BigInt");
|
||||
} else if (prim.isNumber()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Cannot convert number to BigInt");
|
||||
THROW_BUILTIN_ERROR_RETURN_NULL(state, ErrorCode::TypeError, "Cannot convert number to BigInt");
|
||||
} else {
|
||||
ASSERT(prim.isSymbol());
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Cannot convert Symbol to BigInt");
|
||||
THROW_BUILTIN_ERROR_RETURN_NULL(state, ErrorCode::TypeError, "Cannot convert Symbol to BigInt");
|
||||
}
|
||||
ASSERT_NOT_REACHED();
|
||||
return nullptr;
|
||||
|
|
@ -205,23 +208,26 @@ Value Value::ordinaryToPrimitive(ExecutionState& state, PrimitiveTypeHint prefer
|
|||
// Let result be Call(method, O).
|
||||
// If Type(result) is not Object, return result.
|
||||
Value method1 = input->get(state, ObjectPropertyName(methodName1)).value(state, input);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (method1.isCallable()) {
|
||||
Value result = Object::call(state, method1, input, 0, nullptr);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (!result.isObject()) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
Value method2 = input->get(state, ObjectPropertyName(methodName2)).value(state, input);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (method2.isCallable()) {
|
||||
Value result = Object::call(state, method2, input, 0, nullptr);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
if (!result.isObject()) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// Throw a TypeError exception.
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::ObjectToPrimitiveValue);
|
||||
RELEASE_ASSERT_NOT_REACHED();
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::ObjectToPrimitiveValue);
|
||||
}
|
||||
|
||||
// https://www.ecma-international.org/ecma-262/6.0/#sec-toprimitive
|
||||
|
|
@ -243,6 +249,7 @@ Value Value::toPrimitiveSlowCase(ExecutionState& state, PrimitiveTypeHint prefer
|
|||
|
||||
// Let exoticToPrim be GetMethod(input, @@toPrimitive).
|
||||
Value exoticToPrim = Object::getMethod(state, input, ObjectPropertyName(state.context()->vmInstance()->globalSymbols().toPrimitive));
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// If exoticToPrim is not undefined, then
|
||||
if (!exoticToPrim.isUndefined()) {
|
||||
Value hint;
|
||||
|
|
@ -255,12 +262,13 @@ Value Value::toPrimitiveSlowCase(ExecutionState& state, PrimitiveTypeHint prefer
|
|||
}
|
||||
// Let result be Call(exoticToPrim, input, «hint»).
|
||||
Value result = Object::call(state, exoticToPrim, input, 1, &hint);
|
||||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||||
// If Type(result) is not Object, return result.
|
||||
if (!result.isObject()) {
|
||||
return result;
|
||||
}
|
||||
// Throw a TypeError exception.
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::ObjectToPrimitiveValue);
|
||||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::ObjectToPrimitiveValue);
|
||||
}
|
||||
// If hint is "default", let hint be "number".
|
||||
if (preferredType == PreferDefault) {
|
||||
|
|
@ -365,10 +373,14 @@ bool Value::abstractEqualsToSlowCase(ExecutionState& state, const Value& val) co
|
|||
return abstractEqualsTo(state, Value(Value::DoubleToIntConvertibleTestNeeds, val.toNumber(state)));
|
||||
} else if ((selfIsString || selfIsNumber || isSymbol() || selfIsBigInt) && (valIsPointerValue && val.asPointerValue()->isObject())) {
|
||||
// If Type(x) is either String, Number, BigInt, or Symbol and Type(y) is Object, return the result of the comparison x == ? ToPrimitive(y).
|
||||
return abstractEqualsTo(state, val.toPrimitive(state));
|
||||
bool result = abstractEqualsTo(state, val.toPrimitive(state));
|
||||
RETURN_ZERO_IF_PENDING_EXCEPTION
|
||||
return result;
|
||||
} else if ((selfIsPointerValue && asPointerValue()->isObject() && !selfIsString) && (valIsString || valIsNumber || val.isSymbol() || valIsBigInt)) {
|
||||
// If Type(x) is Object and Type(y) is either String, Number, or Symbol, then
|
||||
return toPrimitive(state).abstractEqualsTo(state, val);
|
||||
bool result = toPrimitive(state).abstractEqualsTo(state, val);
|
||||
RETURN_ZERO_IF_PENDING_EXCEPTION
|
||||
return result;
|
||||
} else if (UNLIKELY((selfIsBigInt && valIsNumber) || (selfIsNumber && valIsBigInt))) {
|
||||
// If Type(x) is BigInt and Type(y) is Number, or if Type(x) is Number and Type(y) is BigInt, then
|
||||
// If x or y are any of NaN, +∞, or -∞, return false.
|
||||
|
|
@ -566,7 +578,7 @@ bool Value::instanceOf(ExecutionState& state, const Value& other) const
|
|||
{
|
||||
// If Type(C) is not Object, throw a TypeError exception.
|
||||
if (!other.isObject()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::InstanceOf_NotFunction);
|
||||
THROW_BUILTIN_ERROR_RETURN_ZERO(state, ErrorCode::TypeError, ErrorObject::Messages::InstanceOf_NotFunction);
|
||||
}
|
||||
Object* C = other.asObject();
|
||||
|
||||
|
|
@ -579,16 +591,19 @@ bool Value::instanceOf(ExecutionState& state, const Value& other) const
|
|||
|
||||
// Let instOfHandler be GetMethod(C,@@hasInstance).
|
||||
Value instOfHandler = Object::getMethod(state, other, ObjectPropertyName(state.context()->vmInstance()->globalSymbols().hasInstance));
|
||||
RETURN_ZERO_IF_PENDING_EXCEPTION
|
||||
// If instOfHandler is not undefined, then
|
||||
if (!instOfHandler.isUndefined()) {
|
||||
// Return ToBoolean(Call(instOfHandler, C, «O»)).
|
||||
Value arg[1] = { *this };
|
||||
return Object::call(state, instOfHandler, Value(C), 1, arg).toBoolean(state);
|
||||
Value res = Object::call(state, instOfHandler, Value(C), 1, arg);
|
||||
RETURN_ZERO_IF_PENDING_EXCEPTION
|
||||
return res.toBoolean(state);
|
||||
}
|
||||
|
||||
// If IsCallable(C) is false, throw a TypeError exception.
|
||||
if (!C->isCallable()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::InstanceOf_NotFunction);
|
||||
THROW_BUILTIN_ERROR_RETURN_ZERO(state, ErrorCode::TypeError, ErrorObject::Messages::InstanceOf_NotFunction);
|
||||
}
|
||||
// Return OrdinaryHasInstance(C, O).
|
||||
return C->hasInstance(state, *this);
|
||||
|
|
@ -601,7 +616,7 @@ double Value::toNumberSlowCase(ExecutionState& state) const
|
|||
PointerValue* o = asPointerValue();
|
||||
|
||||
if (UNLIKELY(o->isBigInt())) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Could not convert BigInt to number");
|
||||
THROW_BUILTIN_ERROR_RETURN_ZERO(state, ErrorCode::TypeError, "Could not convert BigInt to number");
|
||||
}
|
||||
|
||||
bool isString = o->isString();
|
||||
|
|
@ -777,12 +792,13 @@ double Value::toNumberSlowCase(ExecutionState& state) const
|
|||
}
|
||||
return val;
|
||||
} else if (isSymbol()) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Cannot convert a Symbol value to a number");
|
||||
ASSERT_NOT_REACHED();
|
||||
THROW_BUILTIN_ERROR_RETURN_ZERO(state, ErrorCode::TypeError, "Cannot convert a Symbol value to a number");
|
||||
} else {
|
||||
// Let primValue be ToPrimitive(argument, hint Number).
|
||||
// Return ToNumber(primValue).
|
||||
return toPrimitive(state, PreferNumber).toNumber(state);
|
||||
Value prim = toPrimitive(state, PreferNumber);
|
||||
RETURN_ZERO_IF_PENDING_EXCEPTION
|
||||
return prim.toNumber(state);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -791,6 +807,10 @@ std::pair<Value, bool> Value::toNumericSlowCase(ExecutionState& state) const
|
|||
{
|
||||
// Let primValue be ? ToPrimitive(value, hint Number).
|
||||
auto primValue = toPrimitive(state, PrimitiveTypeHint::PreferNumber);
|
||||
// return exception
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
return std::make_pair(Value(Value::Exception), false);
|
||||
}
|
||||
// If Type(primValue) is BigInt, return primValue.
|
||||
if (UNLIKELY(primValue.isBigInt())) {
|
||||
return std::make_pair(primValue, true);
|
||||
|
|
@ -851,7 +871,11 @@ uint32_t Value::tryToUseAsIndex32SlowCase(ExecutionState& ec) const
|
|||
if (isSymbol()) {
|
||||
return Value::InvalidIndex32Value;
|
||||
}
|
||||
return toString(ec)->tryToUseAsIndex32();
|
||||
String* str = toString(ec);
|
||||
if (UNLIKELY(ec.hasPendingException())) {
|
||||
return 0;
|
||||
}
|
||||
return str->tryToUseAsIndex32();
|
||||
}
|
||||
|
||||
#if defined(ESCARGOT_ENABLE_TEST)
|
||||
|
|
|
|||
|
|
@ -77,7 +77,8 @@ inline ToType bitwise_cast(FromType from)
|
|||
#define ValueTrue (TagBitTypeOther | (1 << TagTypeShift))
|
||||
#define ValueNull (TagBitTypeOther | (2 << TagTypeShift))
|
||||
#define ValueUndefined (TagBitTypeOther | (3 << TagTypeShift))
|
||||
#define ValueLast ValueUndefined
|
||||
#define ValueException (TagBitTypeOther | (4 << TagTypeShift))
|
||||
#define ValueLast ValueException
|
||||
|
||||
// This special value is never visible to JavaScript code. Empty represents
|
||||
// Array holes, and uninitialized Values, and maps to NULL pointer.
|
||||
|
|
@ -109,7 +110,8 @@ public:
|
|||
enum : uint32_t { BooleanTrueTag = ~ValueTrue };
|
||||
enum : uint32_t { NullTag = ~ValueNull };
|
||||
enum : uint32_t { UndefinedTag = ~ValueUndefined };
|
||||
enum : uint32_t { LowestTag = UndefinedTag };
|
||||
enum : uint32_t { ExceptionTag = ~ValueException };
|
||||
enum : uint32_t { LowestTag = ExceptionTag };
|
||||
|
||||
// Any value which last bit is not set
|
||||
enum { Int32Tag = 0xfffffffe - 0 };
|
||||
|
|
@ -128,6 +130,7 @@ public:
|
|||
enum ForceUninitializedTag { ForceUninitialized };
|
||||
enum FromPayloadTag { FromPayload };
|
||||
enum FromTagTag { FromTag };
|
||||
enum ExceptionInitTag { Exception };
|
||||
|
||||
Value();
|
||||
explicit Value(ForceUninitializedTag);
|
||||
|
|
@ -137,6 +140,7 @@ public:
|
|||
explicit Value(TrueInitTag);
|
||||
explicit Value(FalseInitTag);
|
||||
explicit Value(FromPayloadTag, intptr_t ptr);
|
||||
explicit Value(ExceptionInitTag);
|
||||
#ifdef ESCARGOT_64
|
||||
explicit Value(PointerValue* ptr);
|
||||
Value(const PointerValue* ptr);
|
||||
|
|
@ -227,6 +231,7 @@ public:
|
|||
bool isObject() const;
|
||||
bool isCallable() const;
|
||||
bool isConstructor() const;
|
||||
bool isException() const;
|
||||
|
||||
enum PrimitiveTypeHint { PreferString,
|
||||
PreferNumber,
|
||||
|
|
|
|||
|
|
@ -84,6 +84,12 @@ inline Value::Value(EmptyValueInitTag)
|
|||
u.asBits.payload = 0;
|
||||
}
|
||||
|
||||
inline Value::Value(ExceptionInitTag)
|
||||
{
|
||||
u.asBits.tag = ExceptionTag;
|
||||
u.asBits.payload = 0;
|
||||
}
|
||||
|
||||
inline Value::Value(TrueInitTag)
|
||||
{
|
||||
u.asBits.tag = BooleanTrueTag;
|
||||
|
|
@ -239,6 +245,11 @@ inline bool Value::isEmpty() const
|
|||
return tag() == EmptyValueTag;
|
||||
}
|
||||
|
||||
inline bool Value::isException() const
|
||||
{
|
||||
return tag() == ExceptionTag;
|
||||
}
|
||||
|
||||
ALWAYS_INLINE bool Value::isNumber() const
|
||||
{
|
||||
return isInt32() || isDouble();
|
||||
|
|
@ -373,6 +384,11 @@ inline Value::Value(EmptyValueInitTag)
|
|||
u.asInt64 = ValueEmpty;
|
||||
}
|
||||
|
||||
inline Value::Value(ExceptionInitTag)
|
||||
{
|
||||
u.asInt64 = ValueException;
|
||||
}
|
||||
|
||||
inline Value::Value(TrueInitTag)
|
||||
{
|
||||
u.asInt64 = ValueTrue;
|
||||
|
|
@ -471,6 +487,11 @@ inline bool Value::isEmpty() const
|
|||
return u.asInt64 == ValueEmpty;
|
||||
}
|
||||
|
||||
inline bool Value::isException() const
|
||||
{
|
||||
return u.asInt64 == ValueException;
|
||||
}
|
||||
|
||||
ALWAYS_INLINE bool Value::isNumber() const
|
||||
{
|
||||
#ifdef ESCARGOT_LITTLE_ENDIAN
|
||||
|
|
@ -887,6 +908,9 @@ inline Value::ValueIndex Value::toIndex(ExecutionState& ec) const
|
|||
}
|
||||
|
||||
auto integerIndex = toInteger(ec);
|
||||
if (UNLIKELY(ec.hasPendingException())) {
|
||||
return 0;
|
||||
}
|
||||
Value::ValueIndex index = Value(Value::DoubleToIntConvertibleTestNeeds, integerIndex).toLength(ec);
|
||||
if (UNLIKELY(integerIndex < 0 || integerIndex != index)) {
|
||||
return Value::InvalidIndexValue;
|
||||
|
|
@ -938,6 +962,9 @@ inline double Value::toInteger(ExecutionState& state) const
|
|||
}
|
||||
|
||||
double d = toNumber(state);
|
||||
if (UNLIKELY(state.hasPendingException())) {
|
||||
return 0;
|
||||
}
|
||||
if (std::isnan(d) || d == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -403,6 +403,7 @@ static ValueRef* builtinAddPromiseReactions(ExecutionStateRef* state, ValueRef*
|
|||
promise->then(state, argv[1], argv[2]);
|
||||
} else {
|
||||
state->throwException(TypeErrorObjectRef::create(state, StringRef::emptyString()));
|
||||
return ValueRef::createException();
|
||||
}
|
||||
return ValueRef::createUndefined();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue