summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/runtime/JSCJSValue.cpp
diff options
context:
space:
mode:
authorOswald Buddenhagen <oswald.buddenhagen@qt.io>2017-05-30 12:48:17 +0200
committerOswald Buddenhagen <oswald.buddenhagen@qt.io>2017-05-30 12:48:17 +0200
commit881da28418d380042aa95a97f0cbd42560a64f7c (patch)
treea794dff3274695e99c651902dde93d934ea7a5af /Source/JavaScriptCore/runtime/JSCJSValue.cpp
parent7e104c57a70fdf551bb3d22a5d637cdcbc69dbea (diff)
parent0fcedcd17cc00d3dd44c718b3cb36c1033319671 (diff)
downloadqtwebkit-881da28418d380042aa95a97f0cbd42560a64f7c.tar.gz
Merge 'wip/next' into dev
Change-Id: Iff9ee5e23bb326c4371ec8ed81d56f2f05d680e9
Diffstat (limited to 'Source/JavaScriptCore/runtime/JSCJSValue.cpp')
-rw-r--r--Source/JavaScriptCore/runtime/JSCJSValue.cpp204
1 files changed, 151 insertions, 53 deletions
diff --git a/Source/JavaScriptCore/runtime/JSCJSValue.cpp b/Source/JavaScriptCore/runtime/JSCJSValue.cpp
index 627e9e077..b9dd0a417 100644
--- a/Source/JavaScriptCore/runtime/JSCJSValue.cpp
+++ b/Source/JavaScriptCore/runtime/JSCJSValue.cpp
@@ -25,6 +25,7 @@
#include "BooleanConstructor.h"
#include "BooleanPrototype.h"
+#include "CustomGetterSetter.h"
#include "Error.h"
#include "ExceptionHelpers.h"
#include "GetterSetter.h"
@@ -33,13 +34,12 @@
#include "JSGlobalObject.h"
#include "JSNotAnObject.h"
#include "NumberObject.h"
+#include "StructureInlines.h"
#include <wtf/MathExtras.h>
#include <wtf/StringExtras.h>
namespace JSC {
-static const double D32 = 4294967296.0;
-
// ECMA 9.4
double JSValue::toInteger(ExecState* exec) const
{
@@ -56,6 +56,18 @@ double JSValue::toIntegerPreserveNaN(ExecState* exec) const
return trunc(toNumber(exec));
}
+double JSValue::toLength(ExecState* exec) const
+{
+ // ECMA 7.1.15
+ // http://www.ecma-international.org/ecma-262/6.0/#sec-tolength
+ double d = toInteger(exec);
+ if (d <= 0)
+ return 0.0;
+ if (std::isinf(d))
+ return 9007199254740991.0; // 2 ** 53 - 1
+ return std::min(d, 9007199254740991.0);
+}
+
double JSValue::toNumberSlowCase(ExecState* exec) const
{
ASSERT(!isInt32() && !isDouble());
@@ -63,7 +75,7 @@ double JSValue::toNumberSlowCase(ExecState* exec) const
return asCell()->toNumber(exec);
if (isTrue())
return 1.0;
- return isUndefined() ? QNaN : 0; // null and false both convert to 0.
+ return isUndefined() ? PNaN : 0; // null and false both convert to 0.
}
JSObject* JSValue::toObjectSlowCase(ExecState* exec, JSGlobalObject* globalObject) const
@@ -76,14 +88,18 @@ JSObject* JSValue::toObjectSlowCase(ExecState* exec, JSGlobalObject* globalObjec
return constructBooleanFromImmediateBoolean(exec, globalObject, asValue());
ASSERT(isUndefinedOrNull());
- throwError(exec, createNotAnObjectError(exec, *this));
- return JSNotAnObject::create(exec);
+ VM& vm = exec->vm();
+ vm.throwException(exec, createNotAnObjectError(exec, *this));
+ return JSNotAnObject::create(vm);
}
-JSObject* JSValue::toThisObjectSlowCase(ExecState* exec) const
+JSValue JSValue::toThisSlowCase(ExecState* exec, ECMAMode ecmaMode) const
{
ASSERT(!isCell());
+ if (ecmaMode == StrictMode)
+ return *this;
+
if (isInt32() || isDouble())
return constructNumber(exec, exec->lexicalGlobalObject(), asValue());
if (isTrue() || isFalse())
@@ -95,8 +111,10 @@ JSObject* JSValue::toThisObjectSlowCase(ExecState* exec) const
JSObject* JSValue::synthesizePrototype(ExecState* exec) const
{
if (isCell()) {
- ASSERT(isString());
- return exec->lexicalGlobalObject()->stringPrototype();
+ if (isString())
+ return exec->lexicalGlobalObject()->stringPrototype();
+ ASSERT(isSymbol());
+ return exec->lexicalGlobalObject()->symbolPrototype();
}
if (isNumber())
@@ -105,8 +123,9 @@ JSObject* JSValue::synthesizePrototype(ExecState* exec) const
return exec->lexicalGlobalObject()->booleanPrototype();
ASSERT(isUndefinedOrNull());
- throwError(exec, createNotAnObjectError(exec, *this));
- return JSNotAnObject::create(exec);
+ VM& vm = exec->vm();
+ vm.throwException(exec, createNotAnObjectError(exec, *this));
+ return JSNotAnObject::create(vm);
}
// ECMA 8.7.2
@@ -114,9 +133,8 @@ void JSValue::putToPrimitive(ExecState* exec, PropertyName propertyName, JSValue
{
VM& vm = exec->vm();
- unsigned index = propertyName.asIndex();
- if (index != PropertyName::NotAnIndex) {
- putToPrimitiveByIndex(exec, index, value, slot.isStrictMode());
+ if (Optional<uint32_t> index = parseIndex(propertyName)) {
+ putToPrimitiveByIndex(exec, index.value(), value, slot.isStrictMode());
return;
}
@@ -136,31 +154,22 @@ void JSValue::putToPrimitive(ExecState* exec, PropertyName propertyName, JSValue
for (; ; obj = asObject(prototype)) {
unsigned attributes;
- JSCell* specificValue;
- PropertyOffset offset = obj->structure()->get(vm, propertyName, attributes, specificValue);
+ PropertyOffset offset = obj->structure()->get(vm, propertyName, attributes);
if (offset != invalidOffset) {
if (attributes & ReadOnly) {
if (slot.isStrictMode())
- throwError(exec, createTypeError(exec, StrictModeReadonlyPropertyWriteError));
+ exec->vm().throwException(exec, createTypeError(exec, StrictModeReadonlyPropertyWriteError));
return;
}
JSValue gs = obj->getDirect(offset);
if (gs.isGetterSetter()) {
- JSObject* setterFunc = asGetterSetter(gs)->setter();
- if (!setterFunc) {
- if (slot.isStrictMode())
- throwError(exec, createTypeError(exec, ASCIILiteral("setting a property that has only a getter")));
- return;
- }
-
- CallData callData;
- CallType callType = setterFunc->methodTable()->getCallData(setterFunc, callData);
- MarkedArgumentBuffer args;
- args.append(value);
-
- // If this is WebCore's global object then we need to substitute the shell.
- call(exec, setterFunc, callType, callData, *this, args);
+ callSetter(exec, *this, gs, value, slot.isStrictMode() ? StrictMode : NotStrictMode);
+ return;
+ }
+
+ if (gs.isCustomGetterSetter()) {
+ callCustomSetter(exec, gs, attributes & CustomAccessor, obj, slot.thisValue(), value);
return;
}
@@ -182,7 +191,7 @@ void JSValue::putToPrimitive(ExecState* exec, PropertyName propertyName, JSValue
void JSValue::putToPrimitiveByIndex(ExecState* exec, unsigned propertyName, JSValue value, bool shouldThrow)
{
if (propertyName > MAX_ARRAY_INDEX) {
- PutPropertySlot slot(shouldThrow);
+ PutPropertySlot slot(*this, shouldThrow);
putToPrimitive(exec, Identifier::from(exec, propertyName), value, slot);
return;
}
@@ -196,6 +205,18 @@ void JSValue::putToPrimitiveByIndex(ExecState* exec, unsigned propertyName, JSVa
void JSValue::dump(PrintStream& out) const
{
+ dumpInContext(out, 0);
+}
+
+void JSValue::dumpInContext(PrintStream& out, DumpContext* context) const
+{
+ dumpInContextAssumingStructure(
+ out, context, (!!*this && isCell()) ? asCell()->structure() : nullptr);
+}
+
+void JSValue::dumpInContextAssumingStructure(
+ PrintStream& out, DumpContext* context, Structure* structure) const
+{
if (!*this)
out.print("<JSValue()>");
else if (isInt32())
@@ -212,24 +233,71 @@ void JSValue::dump(PrintStream& out) const
out.printf("Double: %08x:%08x, %lf", u.asTwoInt32s[1], u.asTwoInt32s[0], asDouble());
#endif
} else if (isCell()) {
- if (asCell()->inherits(&JSString::s_info)) {
+ if (structure->classInfo()->isSubClassOf(JSString::info())) {
JSString* string = jsCast<JSString*>(asCell());
- out.print("String: ");
+ out.print("String");
if (string->isRope())
- out.print("(rope) ");
- out.print(string->tryGetValue());
- } else if (asCell()->inherits(&Structure::s_info)) {
- Structure* structure = jsCast<Structure*>(asCell());
- out.print(
- "Structure: ", RawPointer(structure), ": ", structure->classInfo()->className,
- ", ", IndexingTypeDump(structure->indexingTypeIncludingHistory()));
- } else {
+ out.print(" (rope)");
+ const StringImpl* impl = string->tryGetValueImpl();
+ if (impl) {
+ if (impl->isAtomic())
+ out.print(" (atomic)");
+ if (impl->isAtomic())
+ out.print(" (identifier)");
+ if (impl->isSymbol())
+ out.print(" (symbol)");
+ } else
+ out.print(" (unresolved)");
+ out.print(": ", impl);
+ } else if (structure->classInfo()->isSubClassOf(Structure::info()))
+ out.print("Structure: ", inContext(*jsCast<Structure*>(asCell()), context));
+ else {
out.print("Cell: ", RawPointer(asCell()));
- if (isObject() && asObject(*this)->butterfly())
- out.print("->", RawPointer(asObject(*this)->butterfly()));
- out.print(
- " (", RawPointer(asCell()->structure()), ": ", asCell()->structure()->classInfo()->className,
- ", ", IndexingTypeDump(asCell()->structure()->indexingTypeIncludingHistory()), ")");
+ out.print(" (", inContext(*structure, context), ")");
+ }
+#if USE(JSVALUE64)
+ out.print(", ID: ", asCell()->structureID());
+#endif
+ } else if (isTrue())
+ out.print("True");
+ else if (isFalse())
+ out.print("False");
+ else if (isNull())
+ out.print("Null");
+ else if (isUndefined())
+ out.print("Undefined");
+ else
+ out.print("INVALID");
+}
+
+void JSValue::dumpForBacktrace(PrintStream& out) const
+{
+ if (!*this)
+ out.print("<JSValue()>");
+ else if (isInt32())
+ out.printf("%d", asInt32());
+ else if (isDouble())
+ out.printf("%lf", asDouble());
+ else if (isCell()) {
+ if (asCell()->inherits(JSString::info())) {
+ JSString* string = jsCast<JSString*>(asCell());
+ const StringImpl* impl = string->tryGetValueImpl();
+ if (impl)
+ out.print("\"", impl, "\"");
+ else
+ out.print("(unresolved string)");
+ } else if (asCell()->inherits(Structure::info())) {
+ out.print("Structure[ ", asCell()->structure()->classInfo()->className);
+#if USE(JSVALUE64)
+ out.print(" ID: ", asCell()->structureID());
+#endif
+ out.print("]: ", RawPointer(asCell()));
+ } else {
+ out.print("Cell[", asCell()->structure()->classInfo()->className);
+#if USE(JSVALUE64)
+ out.print(" ID: ", asCell()->structureID());
+#endif
+ out.print("]: ", RawPointer(asCell()));
}
} else if (isTrue())
out.print("True");
@@ -293,12 +361,22 @@ bool JSValue::isValidCallee()
return asObject(asCell())->globalObject();
}
-JSString* JSValue::toStringSlowCase(ExecState* exec) const
+JSString* JSValue::toStringSlowCase(ExecState* exec, bool returnEmptyStringOnError) const
{
+ auto errorValue = [&] () -> JSString* {
+ if (returnEmptyStringOnError)
+ return jsEmptyString(exec);
+ return nullptr;
+ };
+
VM& vm = exec->vm();
ASSERT(!isString());
- if (isInt32())
- return jsString(&vm, vm.numericStrings.add(asInt32()));
+ if (isInt32()) {
+ auto integer = asInt32();
+ if (static_cast<unsigned>(integer) <= 9)
+ return vm.smallStrings.singleCharacterString(integer + '0');
+ return jsNontrivialString(&vm, vm.numericStrings.add(integer));
+ }
if (isDouble())
return jsString(&vm, vm.numericStrings.add(asDouble()));
if (isTrue())
@@ -309,18 +387,38 @@ JSString* JSValue::toStringSlowCase(ExecState* exec) const
return vm.smallStrings.nullString();
if (isUndefined())
return vm.smallStrings.undefinedString();
+ if (isSymbol()) {
+ throwTypeError(exec);
+ return errorValue();
+ }
ASSERT(isCell());
JSValue value = asCell()->toPrimitive(exec, PreferString);
- if (exec->hadException())
- return jsEmptyString(exec);
+ if (vm.exception())
+ return errorValue();
ASSERT(!value.isObject());
- return value.toString(exec);
+ JSString* result = value.toString(exec);
+ if (vm.exception())
+ return errorValue();
+ return result;
}
String JSValue::toWTFStringSlowCase(ExecState* exec) const
{
- return inlineJSValueNotStringtoString(*this, exec);
+ VM& vm = exec->vm();
+ if (isInt32())
+ return vm.numericStrings.add(asInt32());
+ if (isDouble())
+ return vm.numericStrings.add(asDouble());
+ if (isTrue())
+ return vm.propertyNames->trueKeyword.string();
+ if (isFalse())
+ return vm.propertyNames->falseKeyword.string();
+ if (isNull())
+ return vm.propertyNames->nullKeyword.string();
+ if (isUndefined())
+ return vm.propertyNames->undefinedKeyword.string();
+ return toString(exec)->value(exec);
}
} // namespace JSC