Added: trunk/JSTests/stress/big-int-json-stringify-to-json.js (0 => 239544)
--- trunk/JSTests/stress/big-int-json-stringify-to-json.js (rev 0)
+++ trunk/JSTests/stress/big-int-json-stringify-to-json.js 2018-12-23 10:09:09 UTC (rev 239544)
@@ -0,0 +1,50 @@
+//@ runBigIntEnabled
+
+function shouldBe(actual, expected)
+{
+ if (actual !== expected)
+ throw new Error('bad value: ' + actual);
+}
+noInline(shouldBe);
+
+function shouldThrow(func, errorMessage) {
+ var errorThrown = false;
+ var error = null;
+ try {
+ func();
+ } catch (e) {
+ errorThrown = true;
+ error = e;
+ }
+ if (!errorThrown)
+ throw new Error('not thrown');
+ if (String(error) !== errorMessage)
+ throw new Error(`bad error: ${String(error)}`);
+}
+noInline(shouldThrow);
+
+var counter = 0;
+BigInt.prototype.toJSON = function () {
+ ++counter;
+ return Number(String(this));
+};
+
+shouldBe(JSON.stringify(0n), `0`);
+shouldBe(counter, 1);
+
+shouldBe(JSON.stringify([0n]), `[0]`);
+shouldBe(counter, 2);
+
+shouldBe(JSON.stringify({hello:0n}), `{"hello":0}`);
+shouldBe(counter, 3);
+
+var bigIntObject = Object(0n);
+
+shouldBe(JSON.stringify(bigIntObject), `0`);
+shouldBe(counter, 4);
+
+shouldBe(JSON.stringify([bigIntObject]), `[0]`);
+shouldBe(counter, 5);
+
+shouldBe(JSON.stringify({hello:bigIntObject}), `{"hello":0}`);
+shouldBe(counter, 6);
Added: trunk/JSTests/stress/big-int-json-stringify.js (0 => 239544)
--- trunk/JSTests/stress/big-int-json-stringify.js (rev 0)
+++ trunk/JSTests/stress/big-int-json-stringify.js 2018-12-23 10:09:09 UTC (rev 239544)
@@ -0,0 +1,52 @@
+//@ runBigIntEnabled
+
+function shouldBe(actual, expected)
+{
+ if (actual !== expected)
+ throw new Error('bad value: ' + actual);
+}
+noInline(shouldBe);
+
+function shouldThrow(func, errorMessage) {
+ var errorThrown = false;
+ var error = null;
+ try {
+ func();
+ } catch (e) {
+ errorThrown = true;
+ error = e;
+ }
+ if (!errorThrown)
+ throw new Error('not thrown');
+ if (String(error) !== errorMessage)
+ throw new Error(`bad error: ${String(error)}`);
+}
+noInline(shouldThrow);
+
+shouldThrow(() => {
+ JSON.stringify(0n);
+}, `TypeError: JSON.stringify cannot serialize BigInt.`);
+
+shouldThrow(() => {
+ JSON.stringify([0n]);
+}, `TypeError: JSON.stringify cannot serialize BigInt.`);
+
+shouldThrow(() => {
+ JSON.stringify({hello:0n});
+}, `TypeError: JSON.stringify cannot serialize BigInt.`);
+
+var bigIntObject = Object(0n);
+
+shouldThrow(() => {
+ JSON.stringify(bigIntObject);
+}, `TypeError: JSON.stringify cannot serialize BigInt.`);
+
+shouldThrow(() => {
+ JSON.stringify([bigIntObject]);
+}, `TypeError: JSON.stringify cannot serialize BigInt.`);
+
+shouldThrow(() => {
+ JSON.stringify({hello:bigIntObject});
+}, `TypeError: JSON.stringify cannot serialize BigInt.`);
+
+
Modified: trunk/Source/_javascript_Core/runtime/JSONObject.cpp (239543 => 239544)
--- trunk/Source/_javascript_Core/runtime/JSONObject.cpp 2018-12-23 06:38:24 UTC (rev 239543)
+++ trunk/Source/_javascript_Core/runtime/JSONObject.cpp 2018-12-23 10:09:09 UTC (rev 239544)
@@ -27,6 +27,7 @@
#include "JSONObject.h"
#include "ArrayConstructor.h"
+#include "BigIntObject.h"
#include "BooleanObject.h"
#include "Error.h"
#include "ExceptionHelpers.h"
@@ -110,8 +111,8 @@
friend class Holder;
- JSValue toJSON(JSObject*, const PropertyNameForFunctionCall&);
- JSValue toJSONImpl(VM&, JSObject*, JSValue toJSONFunction, const PropertyNameForFunctionCall&);
+ JSValue toJSON(JSValue, const PropertyNameForFunctionCall&);
+ JSValue toJSONImpl(VM&, JSValue, JSValue toJSONFunction, const PropertyNameForFunctionCall&);
enum StringifyResult { StringifyFailed, StringifySucceeded, StringifyFailedDueToUndefinedOrSymbolValue };
StringifyResult appendStringifiedValue(StringBuilder&, JSValue, const Holder&, const PropertyNameForFunctionCall&);
@@ -148,8 +149,8 @@
return jsNumber(object->toNumber(exec));
if (object->inherits<StringObject>(vm))
return object->toString(exec);
- if (object->inherits<BooleanObject>(vm))
- return object->toPrimitive(exec);
+ if (object->inherits<BooleanObject>(vm) || object->inherits<BigIntObject>(vm))
+ return jsCast<JSWrapperObject*>(object)->internalValue();
// Do not unwrap SymbolObject to Symbol. It is not performed in the spec.
// http://www.ecma-international.org/ecma-262/6.0/#sec-serializejsonproperty
@@ -286,34 +287,34 @@
RELEASE_AND_RETURN(scope, jsString(m_exec, result.toString()));
}
-ALWAYS_INLINE JSValue Stringifier::toJSON(JSObject* object, const PropertyNameForFunctionCall& propertyName)
+ALWAYS_INLINE JSValue Stringifier::toJSON(JSValue baseValue, const PropertyNameForFunctionCall& propertyName)
{
VM& vm = m_exec->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
scope.assertNoException();
- PropertySlot slot(object, PropertySlot::InternalMethodType::Get);
- bool hasProperty = object->getPropertySlot(m_exec, vm.propertyNames->toJSON, slot);
+ PropertySlot slot(baseValue, PropertySlot::InternalMethodType::Get);
+ bool hasProperty = baseValue.getPropertySlot(m_exec, vm.propertyNames->toJSON, slot);
EXCEPTION_ASSERT(!scope.exception() || !hasProperty);
if (!hasProperty)
- return object;
+ return baseValue;
JSValue toJSONFunction = slot.getValue(m_exec, vm.propertyNames->toJSON);
RETURN_IF_EXCEPTION(scope, { });
- RELEASE_AND_RETURN(scope, toJSONImpl(vm, object, toJSONFunction, propertyName));
+ RELEASE_AND_RETURN(scope, toJSONImpl(vm, baseValue, toJSONFunction, propertyName));
}
-JSValue Stringifier::toJSONImpl(VM& vm, JSObject* object, JSValue toJSONFunction, const PropertyNameForFunctionCall& propertyName)
+JSValue Stringifier::toJSONImpl(VM& vm, JSValue baseValue, JSValue toJSONFunction, const PropertyNameForFunctionCall& propertyName)
{
CallType callType;
CallData callData;
if (!toJSONFunction.isCallable(vm, callType, callData))
- return object;
+ return baseValue;
MarkedArgumentBuffer args;
args.append(propertyName.value(m_exec));
ASSERT(!args.hasOverflowed());
- return call(m_exec, asObject(toJSONFunction), callType, callData, object, args);
+ return call(m_exec, asObject(toJSONFunction), callType, callData, baseValue, args);
}
Stringifier::StringifyResult Stringifier::appendStringifiedValue(StringBuilder& builder, JSValue value, const Holder& holder, const PropertyNameForFunctionCall& propertyName)
@@ -322,8 +323,8 @@
auto scope = DECLARE_THROW_SCOPE(vm);
// Call the toJSON function.
- if (value.isObject()) {
- value = toJSON(asObject(value), propertyName);
+ if (value.isObject() || value.isBigInt()) {
+ value = toJSON(value, propertyName);
RETURN_IF_EXCEPTION(scope, StringifyFailed);
}
@@ -378,6 +379,11 @@
return StringifySucceeded;
}
+ if (value.isBigInt()) {
+ throwTypeError(m_exec, scope, "JSON.stringify cannot serialize BigInt."_s);
+ return StringifyFailed;
+ }
+
if (!value.isObject())
return StringifyFailed;