[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:
HyukWoo Park 2023-07-30 00:28:57 +09:00
commit 26af0cddc6
94 changed files with 3129 additions and 1627 deletions

View file

@ -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>,

View file

@ -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));

View file

@ -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

View file

@ -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;

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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()) {

View file

@ -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

View file

@ -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();
}

View file

@ -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();
}

View file

@ -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) {

View file

@ -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);

View file

@ -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();
}

View file

@ -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;

View file

@ -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);
}

View file

@ -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();

View file

@ -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);

View file

@ -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;

View file

@ -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);
}

View file

@ -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) {

View file

@ -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).

View file

@ -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;

View file

@ -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)

View file

@ -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 patterns [[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);
}

View file

@ -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);

View file

@ -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);

View file

@ -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 "&quot;".
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);

View file

@ -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();
}

View file

@ -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];

View file

@ -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 objects [[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 Os [[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 objects [[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 objects [[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 objects [[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 objects [[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 objects [[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 objects [[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 objects [[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 objects [[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 Os [[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 objects [[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;

View file

@ -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]);

View file

@ -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();

View file

@ -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());

View file

@ -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();

View file

@ -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

View file

@ -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.

View file

@ -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();
}

View file

@ -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)

View file

@ -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);
}
}

View file

@ -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);

View file

@ -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

View file

@ -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();
}

View file

@ -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)

View file

@ -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

View file

@ -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;

View file

@ -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();
}

View file

@ -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");
}
}

View file

@ -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;
}

View file

@ -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);
}
}

View file

@ -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());
}
}

View file

@ -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;

View file

@ -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);

View file

@ -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.

View file

@ -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

View file

@ -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());
}
}

View file

@ -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

View file

@ -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 */

View file

@ -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);

View file

@ -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");

View file

@ -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) \

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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()

View file

@ -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);
}

View file

@ -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)));
}
}

View file

@ -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

View file

@ -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);

View file

@ -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.

View file

@ -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
}
}
}

View file

@ -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();

View file

@ -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;

View file

@ -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);

View file

@ -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

View file

@ -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.

View file

@ -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

View file

@ -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 localEnvs 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
}
}

View file

@ -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;
}

View file

@ -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

View file

@ -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>();
}

View file

@ -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

View file

@ -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);

View file

@ -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) {

View file

@ -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)

View file

@ -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 {

View file

@ -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); \

View file

@ -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)

View file

@ -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;
}

View file

@ -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)

View file

@ -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,

View file

@ -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;
}

View file

@ -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();
}