diff options
author | Oswald Buddenhagen <oswald.buddenhagen@qt.io> | 2017-05-30 12:48:17 +0200 |
---|---|---|
committer | Oswald Buddenhagen <oswald.buddenhagen@qt.io> | 2017-05-30 12:48:17 +0200 |
commit | 881da28418d380042aa95a97f0cbd42560a64f7c (patch) | |
tree | a794dff3274695e99c651902dde93d934ea7a5af /Source/JavaScriptCore/runtime/JSCJSValue.cpp | |
parent | 7e104c57a70fdf551bb3d22a5d637cdcbc69dbea (diff) | |
parent | 0fcedcd17cc00d3dd44c718b3cb36c1033319671 (diff) | |
download | qtwebkit-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.cpp | 204 |
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 |