Boolean.cpp (4923B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 /* 8 * JS boolean implementation. 9 */ 10 11 #include "builtin/Boolean-inl.h" 12 13 #include "jstypes.h" 14 15 #include "jit/InlinableNatives.h" 16 #include "js/PropertySpec.h" 17 #include "util/StringBuilder.h" 18 #include "vm/BigIntType.h" 19 #include "vm/GlobalObject.h" 20 #include "vm/JSContext.h" 21 #include "vm/JSObject.h" 22 23 #include "vm/BooleanObject-inl.h" 24 25 using namespace js; 26 27 const JSClass BooleanObject::class_ = { 28 "Boolean", 29 JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_HAS_CACHED_PROTO(JSProto_Boolean), 30 JS_NULL_CLASS_OPS, 31 &BooleanObject::classSpec_, 32 }; 33 34 MOZ_ALWAYS_INLINE bool IsBoolean(HandleValue v) { 35 return v.isBoolean() || (v.isObject() && v.toObject().is<BooleanObject>()); 36 } 37 38 // ES2020 draft rev ecb4178012d6b4d9abc13fcbd45f5c6394b832ce 39 // 19.4.3 Properties of the Boolean Prototype Object, thisBooleanValue. 40 static MOZ_ALWAYS_INLINE bool ThisBooleanValue(HandleValue val) { 41 // Step 3, the error case, is handled by CallNonGenericMethod. 42 MOZ_ASSERT(IsBoolean(val)); 43 44 // Step 1. 45 if (val.isBoolean()) { 46 return val.toBoolean(); 47 } 48 49 // Step 2. 50 return val.toObject().as<BooleanObject>().unbox(); 51 } 52 53 MOZ_ALWAYS_INLINE bool bool_toSource_impl(JSContext* cx, const CallArgs& args) { 54 bool b = ThisBooleanValue(args.thisv()); 55 56 JSStringBuilder sb(cx); 57 if (!sb.append("(new Boolean(") || !BooleanToStringBuilder(b, sb) || 58 !sb.append("))")) { 59 return false; 60 } 61 62 JSString* str = sb.finishString(); 63 if (!str) { 64 return false; 65 } 66 args.rval().setString(str); 67 return true; 68 } 69 70 static bool bool_toSource(JSContext* cx, unsigned argc, Value* vp) { 71 CallArgs args = CallArgsFromVp(argc, vp); 72 return CallNonGenericMethod<IsBoolean, bool_toSource_impl>(cx, args); 73 } 74 75 // ES2020 draft rev ecb4178012d6b4d9abc13fcbd45f5c6394b832ce 76 // 19.3.3.2 Boolean.prototype.toString ( ) 77 MOZ_ALWAYS_INLINE bool bool_toString_impl(JSContext* cx, const CallArgs& args) { 78 // Step 1. 79 bool b = ThisBooleanValue(args.thisv()); 80 81 // Step 2. 82 args.rval().setString(BooleanToString(cx, b)); 83 return true; 84 } 85 86 static bool bool_toString(JSContext* cx, unsigned argc, Value* vp) { 87 CallArgs args = CallArgsFromVp(argc, vp); 88 return CallNonGenericMethod<IsBoolean, bool_toString_impl>(cx, args); 89 } 90 91 // ES2020 draft rev ecb4178012d6b4d9abc13fcbd45f5c6394b832ce 92 // 19.3.3.3 Boolean.prototype.valueOf ( ) 93 MOZ_ALWAYS_INLINE bool bool_valueOf_impl(JSContext* cx, const CallArgs& args) { 94 // Step 1. 95 args.rval().setBoolean(ThisBooleanValue(args.thisv())); 96 return true; 97 } 98 99 static bool bool_valueOf(JSContext* cx, unsigned argc, Value* vp) { 100 CallArgs args = CallArgsFromVp(argc, vp); 101 return CallNonGenericMethod<IsBoolean, bool_valueOf_impl>(cx, args); 102 } 103 104 static const JSFunctionSpec boolean_methods[] = { 105 JS_FN("toSource", bool_toSource, 0, 0), 106 JS_FN("toString", bool_toString, 0, 0), 107 JS_FN("valueOf", bool_valueOf, 0, 0), 108 JS_FS_END, 109 }; 110 111 // ES2020 draft rev ecb4178012d6b4d9abc13fcbd45f5c6394b832ce 112 // 19.3.1.1 Boolean ( value ) 113 static bool Boolean(JSContext* cx, unsigned argc, Value* vp) { 114 CallArgs args = CallArgsFromVp(argc, vp); 115 116 // Step 1. 117 bool b = args.length() != 0 ? JS::ToBoolean(args[0]) : false; 118 119 if (args.isConstructing()) { 120 // Steps 3-4. 121 RootedObject proto(cx); 122 if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_Boolean, 123 &proto)) { 124 return false; 125 } 126 127 JSObject* obj = BooleanObject::create(cx, b, proto); 128 if (!obj) { 129 return false; 130 } 131 132 // Step 5. 133 args.rval().setObject(*obj); 134 } else { 135 // Step 2. 136 args.rval().setBoolean(b); 137 } 138 return true; 139 } 140 141 JSObject* BooleanObject::createPrototype(JSContext* cx, JSProtoKey key) { 142 BooleanObject* booleanProto = 143 GlobalObject::createBlankPrototype<BooleanObject>(cx, cx->global()); 144 if (!booleanProto) { 145 return nullptr; 146 } 147 booleanProto->setFixedSlot(BooleanObject::PRIMITIVE_VALUE_SLOT, 148 BooleanValue(false)); 149 return booleanProto; 150 } 151 152 const ClassSpec BooleanObject::classSpec_ = { 153 GenericCreateConstructor<Boolean, 1, gc::AllocKind::FUNCTION, 154 &jit::JitInfo_Boolean>, 155 BooleanObject::createPrototype, 156 nullptr, 157 nullptr, 158 boolean_methods, 159 nullptr, 160 }; 161 162 PropertyName* js::BooleanToString(JSContext* cx, bool b) { 163 return b ? cx->names().true_ : cx->names().false_; 164 } 165 166 JS_PUBLIC_API bool js::ToBooleanSlow(HandleValue v) { 167 if (v.isString()) { 168 return v.toString()->length() != 0; 169 } 170 if (v.isBigInt()) { 171 return !v.toBigInt()->isZero(); 172 } 173 174 MOZ_ASSERT(v.isObject()); 175 return !EmulatesUndefined(&v.toObject()); 176 }