|
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
|
2 * vim: set ts=8 sts=4 et sw=4 tw=99: |
|
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 "jsboolinlines.h" |
|
12 |
|
13 #include "jsapi.h" |
|
14 #include "jsatom.h" |
|
15 #include "jscntxt.h" |
|
16 #include "jsobj.h" |
|
17 #include "jstypes.h" |
|
18 |
|
19 #include "vm/GlobalObject.h" |
|
20 #include "vm/ProxyObject.h" |
|
21 #include "vm/StringBuffer.h" |
|
22 |
|
23 #include "vm/BooleanObject-inl.h" |
|
24 |
|
25 using namespace js; |
|
26 using namespace js::types; |
|
27 |
|
28 const Class BooleanObject::class_ = { |
|
29 "Boolean", |
|
30 JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_HAS_CACHED_PROTO(JSProto_Boolean), |
|
31 JS_PropertyStub, /* addProperty */ |
|
32 JS_DeletePropertyStub, /* delProperty */ |
|
33 JS_PropertyStub, /* getProperty */ |
|
34 JS_StrictPropertyStub, /* setProperty */ |
|
35 JS_EnumerateStub, |
|
36 JS_ResolveStub, |
|
37 JS_ConvertStub |
|
38 }; |
|
39 |
|
40 MOZ_ALWAYS_INLINE bool |
|
41 IsBoolean(HandleValue v) |
|
42 { |
|
43 return v.isBoolean() || (v.isObject() && v.toObject().is<BooleanObject>()); |
|
44 } |
|
45 |
|
46 #if JS_HAS_TOSOURCE |
|
47 MOZ_ALWAYS_INLINE bool |
|
48 bool_toSource_impl(JSContext *cx, CallArgs args) |
|
49 { |
|
50 HandleValue thisv = args.thisv(); |
|
51 JS_ASSERT(IsBoolean(thisv)); |
|
52 |
|
53 bool b = thisv.isBoolean() ? thisv.toBoolean() : thisv.toObject().as<BooleanObject>().unbox(); |
|
54 |
|
55 StringBuffer sb(cx); |
|
56 if (!sb.append("(new Boolean(") || !BooleanToStringBuffer(b, sb) || !sb.append("))")) |
|
57 return false; |
|
58 |
|
59 JSString *str = sb.finishString(); |
|
60 if (!str) |
|
61 return false; |
|
62 args.rval().setString(str); |
|
63 return true; |
|
64 } |
|
65 |
|
66 static bool |
|
67 bool_toSource(JSContext *cx, unsigned argc, Value *vp) |
|
68 { |
|
69 CallArgs args = CallArgsFromVp(argc, vp); |
|
70 return CallNonGenericMethod<IsBoolean, bool_toSource_impl>(cx, args); |
|
71 } |
|
72 #endif |
|
73 |
|
74 MOZ_ALWAYS_INLINE bool |
|
75 bool_toString_impl(JSContext *cx, CallArgs args) |
|
76 { |
|
77 HandleValue thisv = args.thisv(); |
|
78 JS_ASSERT(IsBoolean(thisv)); |
|
79 |
|
80 bool b = thisv.isBoolean() ? thisv.toBoolean() : thisv.toObject().as<BooleanObject>().unbox(); |
|
81 args.rval().setString(js_BooleanToString(cx, b)); |
|
82 return true; |
|
83 } |
|
84 |
|
85 static bool |
|
86 bool_toString(JSContext *cx, unsigned argc, Value *vp) |
|
87 { |
|
88 CallArgs args = CallArgsFromVp(argc, vp); |
|
89 return CallNonGenericMethod<IsBoolean, bool_toString_impl>(cx, args); |
|
90 } |
|
91 |
|
92 MOZ_ALWAYS_INLINE bool |
|
93 bool_valueOf_impl(JSContext *cx, CallArgs args) |
|
94 { |
|
95 HandleValue thisv = args.thisv(); |
|
96 JS_ASSERT(IsBoolean(thisv)); |
|
97 |
|
98 bool b = thisv.isBoolean() ? thisv.toBoolean() : thisv.toObject().as<BooleanObject>().unbox(); |
|
99 args.rval().setBoolean(b); |
|
100 return true; |
|
101 } |
|
102 |
|
103 static bool |
|
104 bool_valueOf(JSContext *cx, unsigned argc, Value *vp) |
|
105 { |
|
106 CallArgs args = CallArgsFromVp(argc, vp); |
|
107 return CallNonGenericMethod<IsBoolean, bool_valueOf_impl>(cx, args); |
|
108 } |
|
109 |
|
110 static const JSFunctionSpec boolean_methods[] = { |
|
111 #if JS_HAS_TOSOURCE |
|
112 JS_FN(js_toSource_str, bool_toSource, 0, 0), |
|
113 #endif |
|
114 JS_FN(js_toString_str, bool_toString, 0, 0), |
|
115 JS_FS_END |
|
116 }; |
|
117 |
|
118 static bool |
|
119 Boolean(JSContext *cx, unsigned argc, Value *vp) |
|
120 { |
|
121 CallArgs args = CallArgsFromVp(argc, vp); |
|
122 |
|
123 bool b = args.length() != 0 ? JS::ToBoolean(args[0]) : false; |
|
124 |
|
125 if (args.isConstructing()) { |
|
126 JSObject *obj = BooleanObject::create(cx, b); |
|
127 if (!obj) |
|
128 return false; |
|
129 args.rval().setObject(*obj); |
|
130 } else { |
|
131 args.rval().setBoolean(b); |
|
132 } |
|
133 return true; |
|
134 } |
|
135 |
|
136 JSObject * |
|
137 js_InitBooleanClass(JSContext *cx, HandleObject obj) |
|
138 { |
|
139 JS_ASSERT(obj->isNative()); |
|
140 |
|
141 Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>()); |
|
142 |
|
143 RootedObject booleanProto (cx, global->createBlankPrototype(cx, &BooleanObject::class_)); |
|
144 if (!booleanProto) |
|
145 return nullptr; |
|
146 booleanProto->setFixedSlot(BooleanObject::PRIMITIVE_VALUE_SLOT, BooleanValue(false)); |
|
147 |
|
148 RootedFunction ctor(cx, global->createConstructor(cx, Boolean, cx->names().Boolean, 1)); |
|
149 if (!ctor) |
|
150 return nullptr; |
|
151 |
|
152 if (!LinkConstructorAndPrototype(cx, ctor, booleanProto)) |
|
153 return nullptr; |
|
154 |
|
155 if (!DefinePropertiesAndBrand(cx, booleanProto, nullptr, boolean_methods)) |
|
156 return nullptr; |
|
157 |
|
158 Handle<PropertyName*> valueOfName = cx->names().valueOf; |
|
159 RootedFunction |
|
160 valueOf(cx, NewFunction(cx, NullPtr(), bool_valueOf, 0, JSFunction::NATIVE_FUN, |
|
161 global, valueOfName)); |
|
162 if (!valueOf) |
|
163 return nullptr; |
|
164 |
|
165 RootedValue value(cx, ObjectValue(*valueOf)); |
|
166 if (!JSObject::defineProperty(cx, booleanProto, valueOfName, value, |
|
167 JS_PropertyStub, JS_StrictPropertyStub, 0)) |
|
168 { |
|
169 return nullptr; |
|
170 } |
|
171 |
|
172 if (!GlobalObject::initBuiltinConstructor(cx, global, JSProto_Boolean, ctor, booleanProto)) |
|
173 return nullptr; |
|
174 |
|
175 return booleanProto; |
|
176 } |
|
177 |
|
178 JSString * |
|
179 js_BooleanToString(ExclusiveContext *cx, bool b) |
|
180 { |
|
181 return b ? cx->names().true_ : cx->names().false_; |
|
182 } |
|
183 |
|
184 JS_PUBLIC_API(bool) |
|
185 js::ToBooleanSlow(HandleValue v) |
|
186 { |
|
187 if (v.isString()) |
|
188 return v.toString()->length() != 0; |
|
189 |
|
190 JS_ASSERT(v.isObject()); |
|
191 return !EmulatesUndefined(&v.toObject()); |
|
192 } |
|
193 |
|
194 /* |
|
195 * This slow path is only ever taken for proxies wrapping Boolean objects |
|
196 * The only caller of the fast path, JSON's PreprocessValue, ensures that. |
|
197 */ |
|
198 bool |
|
199 js::BooleanGetPrimitiveValueSlow(HandleObject wrappedBool) |
|
200 { |
|
201 JSObject *obj = wrappedBool->as<ProxyObject>().target(); |
|
202 JS_ASSERT(obj); |
|
203 return obj->as<BooleanObject>().unbox(); |
|
204 } |