Skip to content

Commit f2aca21

Browse files
committed
Implement CallBuiltin instruction
1 parent c163676 commit f2aca21

12 files changed

Lines changed: 929 additions & 33 deletions

File tree

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
(function() {
2+
let sum = 0;
3+
for (let i = 0; i < 1000; i++) {
4+
sum += Math.abs(-i);
5+
sum += Math.floor(i + 0.5);
6+
sum += Math.ceil(i - 0.5);
7+
sum += Math.round(i + 0.3);
8+
sum += Math.sqrt(i);
9+
sum += Math.pow(i, 2);
10+
sum += Math.log(i + 1);
11+
sum += Math.exp(i / 100);
12+
sum += Math.log2(i + 1);
13+
sum += Math.log10(i + 1);
14+
sum += Math.sin(i);
15+
sum += Math.cos(i);
16+
sum += Math.max(i, i + 1);
17+
sum += Math.min(i, i + 1);
18+
}
19+
return sum;
20+
})();

core/engine/benches/full.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,8 @@ full_benchmarks!(
117117
{"String Object Access", string_object_access},
118118
{"Arithmetic operations", arithmetic_operations},
119119
{"Clean js", clean_js},
120-
{"Mini js", mini_js}
120+
{"Mini js", mini_js},
121+
{"Math builtins", math_builtins}
121122
);
122123

123124
criterion_group!(

core/engine/src/builtins/math/mod.rs

Lines changed: 214 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,146 @@ mod tests;
2727
pub(crate) struct Math;
2828

2929
impl IntrinsicObject for Math {
30+
#[allow(clippy::similar_names)]
3031
fn init(realm: &Realm) {
3132
let attribute = Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::PERMANENT;
33+
34+
let math_intrinsics = realm.intrinsics().objects().math();
35+
36+
let abs_function = BuiltInBuilder::callable_with_object(
37+
realm,
38+
math_intrinsics.abs().clone().into(),
39+
Self::abs,
40+
)
41+
.name(js_string!("abs"))
42+
.length(1)
43+
.build();
44+
45+
let floor_function = BuiltInBuilder::callable_with_object(
46+
realm,
47+
math_intrinsics.floor().clone().into(),
48+
Self::floor,
49+
)
50+
.name(js_string!("floor"))
51+
.length(1)
52+
.build();
53+
54+
let ceil_function = BuiltInBuilder::callable_with_object(
55+
realm,
56+
math_intrinsics.ceil().clone().into(),
57+
Self::ceil,
58+
)
59+
.name(js_string!("ceil"))
60+
.length(1)
61+
.build();
62+
63+
let round_function = BuiltInBuilder::callable_with_object(
64+
realm,
65+
math_intrinsics.round().clone().into(),
66+
Self::round,
67+
)
68+
.name(js_string!("round"))
69+
.length(1)
70+
.build();
71+
72+
let sqrt_function = BuiltInBuilder::callable_with_object(
73+
realm,
74+
math_intrinsics.sqrt().clone().into(),
75+
Self::sqrt,
76+
)
77+
.name(js_string!("sqrt"))
78+
.length(1)
79+
.build();
80+
81+
let pow_function = BuiltInBuilder::callable_with_object(
82+
realm,
83+
math_intrinsics.pow().clone().into(),
84+
Self::pow,
85+
)
86+
.name(js_string!("pow"))
87+
.length(2)
88+
.build();
89+
90+
let random_function = BuiltInBuilder::callable_with_object(
91+
realm,
92+
math_intrinsics.random().clone().into(),
93+
Self::random,
94+
)
95+
.name(js_string!("random"))
96+
.length(0)
97+
.build();
98+
99+
let log_function = BuiltInBuilder::callable_with_object(
100+
realm,
101+
math_intrinsics.log().clone().into(),
102+
Self::log,
103+
)
104+
.name(js_string!("log"))
105+
.length(1)
106+
.build();
107+
108+
let exp_function = BuiltInBuilder::callable_with_object(
109+
realm,
110+
math_intrinsics.exp().clone().into(),
111+
Self::exp,
112+
)
113+
.name(js_string!("exp"))
114+
.length(1)
115+
.build();
116+
117+
let log2_function = BuiltInBuilder::callable_with_object(
118+
realm,
119+
math_intrinsics.log2().clone().into(),
120+
Self::log2,
121+
)
122+
.name(js_string!("log2"))
123+
.length(1)
124+
.build();
125+
126+
let log10_function = BuiltInBuilder::callable_with_object(
127+
realm,
128+
math_intrinsics.log10().clone().into(),
129+
Self::log10,
130+
)
131+
.name(js_string!("log10"))
132+
.length(1)
133+
.build();
134+
135+
let max_function = BuiltInBuilder::callable_with_object(
136+
realm,
137+
math_intrinsics.max().clone().into(),
138+
Self::max,
139+
)
140+
.name(js_string!("max"))
141+
.length(2)
142+
.build();
143+
144+
let min_function = BuiltInBuilder::callable_with_object(
145+
realm,
146+
math_intrinsics.min().clone().into(),
147+
Self::min,
148+
)
149+
.name(js_string!("min"))
150+
.length(2)
151+
.build();
152+
153+
let sin_function = BuiltInBuilder::callable_with_object(
154+
realm,
155+
math_intrinsics.sin().clone().into(),
156+
Self::sin,
157+
)
158+
.name(js_string!("sin"))
159+
.length(1)
160+
.build();
161+
162+
let cos_function = BuiltInBuilder::callable_with_object(
163+
realm,
164+
math_intrinsics.cos().clone().into(),
165+
Self::cos,
166+
)
167+
.name(js_string!("cos"))
168+
.length(1)
169+
.build();
32170
let builder = BuiltInBuilder::with_intrinsic::<Self>(realm)
33171
.static_property(js_string!("E"), std::f64::consts::E, attribute)
34172
.static_property(js_string!("LN10"), std::f64::consts::LN_10, attribute)
@@ -42,7 +180,11 @@ impl IntrinsicObject for Math {
42180
attribute,
43181
)
44182
.static_property(js_string!("SQRT2"), std::f64::consts::SQRT_2, attribute)
45-
.static_method(Self::abs, js_string!("abs"), 1)
183+
.static_property(
184+
js_string!("abs"),
185+
abs_function,
186+
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
187+
)
46188
.static_method(Self::acos, js_string!("acos"), 1)
47189
.static_method(Self::acosh, js_string!("acosh"), 1)
48190
.static_method(Self::asin, js_string!("asin"), 1)
@@ -51,29 +193,85 @@ impl IntrinsicObject for Math {
51193
.static_method(Self::atanh, js_string!("atanh"), 1)
52194
.static_method(Self::atan2, js_string!("atan2"), 2)
53195
.static_method(Self::cbrt, js_string!("cbrt"), 1)
54-
.static_method(Self::ceil, js_string!("ceil"), 1)
196+
.static_property(
197+
js_string!("ceil"),
198+
ceil_function,
199+
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
200+
)
55201
.static_method(Self::clz32, js_string!("clz32"), 1)
56-
.static_method(Self::cos, js_string!("cos"), 1)
202+
.static_property(
203+
js_string!("cos"),
204+
cos_function,
205+
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
206+
)
57207
.static_method(Self::cosh, js_string!("cosh"), 1)
58-
.static_method(Self::exp, js_string!("exp"), 1)
208+
.static_property(
209+
js_string!("exp"),
210+
exp_function,
211+
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
212+
)
59213
.static_method(Self::expm1, js_string!("expm1"), 1)
60-
.static_method(Self::floor, js_string!("floor"), 1)
214+
.static_property(
215+
js_string!("floor"),
216+
floor_function,
217+
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
218+
)
61219
.static_method(Self::fround, js_string!("fround"), 1)
62220
.static_method(Self::hypot, js_string!("hypot"), 2)
63221
.static_method(Self::imul, js_string!("imul"), 2)
64-
.static_method(Self::log, js_string!("log"), 1)
222+
.static_property(
223+
js_string!("log"),
224+
log_function,
225+
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
226+
)
227+
.static_property(
228+
js_string!("log2"),
229+
log2_function,
230+
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
231+
)
232+
.static_property(
233+
js_string!("log10"),
234+
log10_function,
235+
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
236+
)
65237
.static_method(Self::log1p, js_string!("log1p"), 1)
66-
.static_method(Self::log10, js_string!("log10"), 1)
67-
.static_method(Self::log2, js_string!("log2"), 1)
68-
.static_method(Self::max, js_string!("max"), 2)
69-
.static_method(Self::min, js_string!("min"), 2)
70-
.static_method(Self::pow, js_string!("pow"), 2)
71-
.static_method(Self::random, js_string!("random"), 0)
72-
.static_method(Self::round, js_string!("round"), 1)
238+
.static_property(
239+
js_string!("max"),
240+
max_function,
241+
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
242+
)
243+
.static_property(
244+
js_string!("min"),
245+
min_function,
246+
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
247+
)
248+
.static_property(
249+
js_string!("pow"),
250+
pow_function,
251+
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
252+
)
253+
.static_property(
254+
js_string!("random"),
255+
random_function,
256+
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
257+
)
258+
.static_property(
259+
js_string!("round"),
260+
round_function,
261+
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
262+
)
73263
.static_method(Self::sign, js_string!("sign"), 1)
74-
.static_method(Self::sin, js_string!("sin"), 1)
264+
.static_property(
265+
js_string!("sin"),
266+
sin_function,
267+
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
268+
)
75269
.static_method(Self::sinh, js_string!("sinh"), 1)
76-
.static_method(Self::sqrt, js_string!("sqrt"), 1)
270+
.static_property(
271+
js_string!("sqrt"),
272+
sqrt_function,
273+
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
274+
)
77275
.static_method(Self::tan, js_string!("tan"), 1)
78276
.static_method(Self::tanh, js_string!("tanh"), 1)
79277
.static_method(Self::trunc, js_string!("trunc"), 1)
@@ -93,7 +291,7 @@ impl IntrinsicObject for Math {
93291
}
94292

95293
fn get(intrinsics: &Intrinsics) -> JsObject {
96-
intrinsics.objects().math()
294+
intrinsics.objects().math().object()
97295
}
98296
}
99297

core/engine/src/builtins/math/tests.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,18 +228,50 @@ fn log2() {
228228
#[test]
229229
fn max() {
230230
run_test_actions([
231+
TestAction::assert_eq("Math.max()", f64::NEG_INFINITY),
231232
TestAction::assert_eq("Math.max(10, 20)", 20.0),
232233
TestAction::assert_eq("Math.max(-10, -20)", -10.0),
233234
TestAction::assert_eq("Math.max(-10, 20)", 20.0),
235+
TestAction::assert_eq("Math.max(1, 2, 3, 4, 5)", 5.0),
236+
TestAction::assert_eq("Math.max('5', 2)", 5.0),
237+
TestAction::assert_with_op("Math.max(NaN, 1)", |value, _| {
238+
value.as_number().unwrap().is_nan()
239+
}),
240+
TestAction::assert_with_op("Math.max(0, -0)", |value, _| {
241+
let number = value.as_number().unwrap();
242+
number == 0.0 && number.is_sign_positive()
243+
}),
244+
TestAction::assert_eq("Math.max(-Infinity, Infinity)", f64::INFINITY),
245+
TestAction::assert_with_op(
246+
"(function () { const obj = { valueOf() { return 7; } }; return Math.max(obj, 3); })()",
247+
|value, _| value.as_number().unwrap() == 7.0,
248+
),
249+
TestAction::assert_eq("Math.max(true, false)", 1.0),
234250
]);
235251
}
236252

237253
#[test]
238254
fn min() {
239255
run_test_actions([
256+
TestAction::assert_eq("Math.min()", f64::INFINITY),
240257
TestAction::assert_eq("Math.min(10, 20)", 10.0),
241258
TestAction::assert_eq("Math.min(-10, -20)", -20.0),
242259
TestAction::assert_eq("Math.min(-10, 20)", -10.0),
260+
TestAction::assert_eq("Math.min(1, 2, 3, -4, 5)", -4.0),
261+
TestAction::assert_eq("Math.min('5', 2)", 2.0),
262+
TestAction::assert_with_op("Math.min(NaN, 1)", |value, _| {
263+
value.as_number().unwrap().is_nan()
264+
}),
265+
TestAction::assert_with_op("Math.min(0, -0)", |value, _| {
266+
let number = value.as_number().unwrap();
267+
number == 0.0 && number.is_sign_negative()
268+
}),
269+
TestAction::assert_eq("Math.min(-Infinity, Infinity)", f64::NEG_INFINITY),
270+
TestAction::assert_with_op(
271+
"(function () { const obj = { valueOf() { return -7; } }; return Math.min(obj, 3); })()",
272+
|value, _| value.as_number().unwrap() == -7.0,
273+
),
274+
TestAction::assert_eq("Math.min(true, false)", 0.0),
243275
]);
244276
}
245277

0 commit comments

Comments
 (0)