Browse Source

LibJS/JIT: Add a builtin for Math.abs

Simon Wanner 1 year ago
parent
commit
6c8ab1ca0d

+ 17 - 0
Userland/Libraries/LibJIT/X86_64/Assembler.h

@@ -582,6 +582,15 @@ struct X86_64Assembler {
         emit_modrm_slash(0, dst);
         emit_modrm_slash(0, dst);
     }
     }
 
 
+    void mov_if(Condition condition, Operand dst, Operand src)
+    {
+        VERIFY(dst.type == Operand::Type::Reg && src.type == Operand::Type::Reg);
+        emit_rex_for_rm(dst, src, REX_W::Yes);
+        emit8(0x0f);
+        emit8(0x40 | to_underlying(condition));
+        emit_modrm_rm(dst, src);
+    }
+
     void sign_extend_32_to_64_bits(Reg reg)
     void sign_extend_32_to_64_bits(Reg reg)
     {
     {
         mov32(Operand::Register(reg), Operand::Register(reg), Extension::SignExtend);
         mov32(Operand::Register(reg), Operand::Register(reg), Extension::SignExtend);
@@ -989,6 +998,14 @@ struct X86_64Assembler {
         }
         }
     }
     }
 
 
+    void neg32(Operand reg)
+    {
+        VERIFY(reg.type == Operand::Type::Reg);
+        emit_rex_for_slash(reg, REX_W::No);
+        emit8(0xf7);
+        emit_modrm_slash(3, reg);
+    }
+
     void convert_i32_to_double(Operand dst, Operand src)
     void convert_i32_to_double(Operand dst, Operand src)
     {
     {
         VERIFY(dst.type == Operand::Type::FReg);
         VERIFY(dst.type == Operand::Type::FReg);

+ 2 - 1
Userland/Libraries/LibJS/Bytecode/Builtins.h

@@ -12,7 +12,8 @@
 namespace JS::Bytecode {
 namespace JS::Bytecode {
 
 
 // TitleCaseName, snake_case_name, base, property, argument_count
 // TitleCaseName, snake_case_name, base, property, argument_count
-#define JS_ENUMERATE_BUILTINS(O)
+#define JS_ENUMERATE_BUILTINS(O) \
+    O(MathAbs, math_abs, Math, abs, 1)
 
 
 enum class Builtin {
 enum class Builtin {
 #define DEFINE_BUILTIN_ENUM(name, ...) name,
 #define DEFINE_BUILTIN_ENUM(name, ...) name,

+ 38 - 1
Userland/Libraries/LibJS/JIT/Compiler.cpp

@@ -2587,7 +2587,7 @@ void Compiler::compile_call(Bytecode::Op::Call const& op)
     end.link(m_assembler);
     end.link(m_assembler);
 }
 }
 
 
-void Compiler::compile_builtin(Bytecode::Builtin builtin, [[maybe_unused]] Assembler::Label& slow_case, [[maybe_unused]] Assembler::Label& end)
+void Compiler::compile_builtin(Bytecode::Builtin builtin, Assembler::Label& slow_case, Assembler::Label& end)
 {
 {
     switch (builtin) {
     switch (builtin) {
 #    define DEFINE_BUILTIN_CASE(name, snake_case_name, ...) \
 #    define DEFINE_BUILTIN_CASE(name, snake_case_name, ...) \
@@ -2601,6 +2601,43 @@ void Compiler::compile_builtin(Bytecode::Builtin builtin, [[maybe_unused]] Assem
     }
     }
 }
 }
 
 
+void Compiler::compile_builtin_math_abs(Assembler::Label& slow_case, Assembler::Label& end)
+{
+    branch_if_int32(ARG2, [&] {
+        // ARG2 &= 0xffffffff
+        m_assembler.mov32(Assembler::Operand::Register(ARG2), Assembler::Operand::Register(ARG2), Assembler::Extension::SignExtend);
+
+        // if (ARG2 == INT32_MIN) goto slow_case;
+        m_assembler.jump_if(
+            Assembler::Operand::Register(ARG2),
+            Assembler::Condition::EqualTo,
+            Assembler::Operand::Imm(NumericLimits<i32>::min()),
+            slow_case);
+
+        // accumulator = ARG2 < 0 ? -ARG2 : ARG2;
+        m_assembler.mov(Assembler::Operand::Register(CACHED_ACCUMULATOR), Assembler::Operand::Register(ARG2));
+        m_assembler.neg32(Assembler::Operand::Register(CACHED_ACCUMULATOR));
+        m_assembler.mov_if(Assembler::Condition::SignedLessThan, Assembler::Operand::Register(CACHED_ACCUMULATOR), Assembler::Operand::Register(ARG2));
+
+        // accumulator |= SHIFTED_INT32_TAG;
+        m_assembler.mov(Assembler::Operand::Register(GPR0), Assembler::Operand::Imm(SHIFTED_INT32_TAG));
+        m_assembler.bitwise_or(Assembler::Operand::Register(CACHED_ACCUMULATOR), Assembler::Operand::Register(GPR0));
+
+        m_assembler.jump(end);
+    });
+
+    // if (ARG2.is_double()) goto slow_case;
+    m_assembler.mov(Assembler::Operand::Register(GPR0), Assembler::Operand::Imm(CANON_NAN_BITS));
+    jump_if_not_double(ARG2, GPR0, GPR1, slow_case);
+
+    // accumulator = ARG2 & 0x7fffffffffffffff
+    m_assembler.mov(Assembler::Operand::Register(GPR0), Assembler::Operand::Imm(0x7fffffffffffffff));
+    m_assembler.bitwise_and(Assembler::Operand::Register(ARG2), Assembler::Operand::Register(GPR0));
+    store_accumulator(ARG2);
+
+    m_assembler.jump(end);
+}
+
 static Value cxx_call_with_argument_array(VM& vm, Value arguments, Value callee, Value this_value, Bytecode::Op::CallType call_type, Optional<Bytecode::StringTableIndex> const& expression_string)
 static Value cxx_call_with_argument_array(VM& vm, Value arguments, Value callee, Value this_value, Bytecode::Op::CallType call_type, Optional<Bytecode::StringTableIndex> const& expression_string)
 {
 {
     TRY_OR_SET_EXCEPTION(throw_if_needed_for_call(vm.bytecode_interpreter(), callee, call_type, expression_string));
     TRY_OR_SET_EXCEPTION(throw_if_needed_for_call(vm.bytecode_interpreter(), callee, call_type, expression_string));

+ 1 - 1
Userland/Libraries/LibJS/Runtime/MathObject.cpp

@@ -27,7 +27,7 @@ void MathObject::initialize(Realm& realm)
     auto& vm = this->vm();
     auto& vm = this->vm();
     Base::initialize(realm);
     Base::initialize(realm);
     u8 attr = Attribute::Writable | Attribute::Configurable;
     u8 attr = Attribute::Writable | Attribute::Configurable;
-    define_native_function(realm, vm.names.abs, abs, 1, attr);
+    define_native_function(realm, vm.names.abs, abs, 1, attr, Bytecode::Builtin::MathAbs);
     define_native_function(realm, vm.names.random, random, 0, attr);
     define_native_function(realm, vm.names.random, random, 0, attr);
     define_native_function(realm, vm.names.sqrt, sqrt, 1, attr);
     define_native_function(realm, vm.names.sqrt, sqrt, 1, attr);
     define_native_function(realm, vm.names.floor, floor, 1, attr);
     define_native_function(realm, vm.names.floor, floor, 1, attr);