diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3216455dc924..ecfc4210c569 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -16,6 +16,7 @@ Compatibility:
 
 Performance:
 
+* Improve `Truffle::FeatureLoader.loaded_feature_path` by removing expensive string ops from a loop. Speeds up feature lookup time (#3010, @itarato).
 
 Changes:
 
diff --git a/spec/truffle/kernel/feature_loader_spec.rb b/spec/truffle/kernel/feature_loader_spec.rb
index 5581281d77e7..df890df2c71a 100644
--- a/spec/truffle/kernel/feature_loader_spec.rb
+++ b/spec/truffle/kernel/feature_loader_spec.rb
@@ -53,27 +53,27 @@
   end
 end
 
-describe "Truffle::FeatureLoader.loaded_feature_path" do
+describe "Truffle::FeatureLoader.feature_path_loaded?" do
   it "returns path for matching feature" do
     load_path = ["/path/ruby/lib/ruby/2.6.0"]
     loaded_feature = "/path/ruby/lib/ruby/2.6.0/benchmark.rb"
     feature = "benchmark"
-    path = Truffle::FeatureLoader.loaded_feature_path(loaded_feature, feature, load_path)
-    path.should == load_path[0]
+    path = Truffle::FeatureLoader.feature_path_loaded?(loaded_feature, feature, load_path)
+    path.should be_true
 
     feature = "benchmark.rb"
-    path = Truffle::FeatureLoader.loaded_feature_path(loaded_feature, feature, load_path)
-    path.should == load_path[0]
+    path = Truffle::FeatureLoader.feature_path_loaded?(loaded_feature, feature, load_path)
+    path.should be_true
   end
 
-  it "returns nil for missing features" do
+  it "returns false for missing features" do
     load_path = ["/path/ruby/lib/ruby/2.6.0"]
-    path = Truffle::FeatureLoader.loaded_feature_path("/path/ruby/lib/ruby/2.6.0/benchmark.rb", "missing", load_path)
-    path.should == nil
+    path = Truffle::FeatureLoader.feature_path_loaded?("/path/ruby/lib/ruby/2.6.0/benchmark.rb", "missing", load_path)
+    path.should be_false
 
     long_feature = "/path/ruby/lib/ruby/2.6.0/extra-path/benchmark.rb"
-    path = Truffle::FeatureLoader.loaded_feature_path("/path/ruby/lib/ruby/2.6.0/benchmark.rb", long_feature, load_path)
-    path.should == nil
+    path = Truffle::FeatureLoader.feature_path_loaded?("/path/ruby/lib/ruby/2.6.0/benchmark.rb", long_feature, load_path)
+    path.should be_false
   end
 
   it "returns correct paths for non-rb paths" do
@@ -81,16 +81,16 @@
     loaded_feature = "/path/ruby/lib/ruby/2.6.0/benchmark.so"
 
     feature = "benchmark"
-    path = Truffle::FeatureLoader.loaded_feature_path(loaded_feature, feature, load_path)
-    path.should == load_path[0]
+    path = Truffle::FeatureLoader.feature_path_loaded?(loaded_feature, feature, load_path)
+    path.should be_true
 
     feature = "benchmark.so"
-    path = Truffle::FeatureLoader.loaded_feature_path(loaded_feature, feature, load_path)
-    path.should == load_path[0]
+    path = Truffle::FeatureLoader.feature_path_loaded?(loaded_feature, feature, load_path)
+    path.should be_true
 
     feature = "benchmark.rb"
-    path = Truffle::FeatureLoader.loaded_feature_path(loaded_feature, feature, load_path)
-    path.should == nil
+    path = Truffle::FeatureLoader.feature_path_loaded?(loaded_feature, feature, load_path)
+    path.should be_false
   end
 
 end
diff --git a/src/main/ruby/truffleruby/core/truffle/feature_loader.rb b/src/main/ruby/truffleruby/core/truffle/feature_loader.rb
index bcc0a6aff702..8ecdbd8cacbc 100644
--- a/src/main/ruby/truffleruby/core/truffle/feature_loader.rb
+++ b/src/main/ruby/truffleruby/core/truffle/feature_loader.rb
@@ -165,16 +165,16 @@ def self.feature_provided?(feature, expanded)
               loaded_feature = $LOADED_FEATURES[fe.index]
 
               next if loaded_feature.size < feature.size
-              feature_path = if loaded_feature.start_with?(feature)
-                               feature
-                             else
-                               if expanded
-                                 nil
-                               else
-                                 loaded_feature_path(loaded_feature, feature, get_expanded_load_path)
-                               end
-                             end
-              if feature_path
+              found_feature_path = if loaded_feature.start_with?(feature)
+                                     true
+                                   else
+                                     if expanded
+                                       false
+                                     else
+                                       feature_path_loaded?(loaded_feature, feature, get_expanded_load_path)
+                                     end
+                                   end
+              if found_feature_path
                 loaded_feature_ext = extension_symbol(loaded_feature)
                 if !loaded_feature_ext
                   return :unknown unless feature_ext
@@ -198,11 +198,18 @@ def self.feature_provided?(feature, expanded)
     # MRI: loaded_feature_path
     # Search if $LOAD_PATH[i]/feature corresponds to loaded_feature.
     # Returns the $LOAD_PATH entry containing feature.
-    def self.loaded_feature_path(loaded_feature, feature, load_path)
+    def self.feature_path_loaded?(loaded_feature, feature, load_path)
       name_ext = extension(loaded_feature)
-      load_path.find do |p|
-        loaded_feature == "#{p}/#{feature}#{name_ext}" || loaded_feature == "#{p}/#{feature}"
+
+      if name_ext && (suffix_with_ext = "/#{feature}#{name_ext}") && loaded_feature.end_with?(suffix_with_ext)
+        path = loaded_feature[0...-suffix_with_ext.size]
+      elsif loaded_feature.end_with?(feature) && loaded_feature.getbyte(-(feature.bytesize + 1)) == 47 # '/'.ord = 47
+        path = loaded_feature[0...-(feature.size + 1)]
+      else
+        return false
       end
+
+      load_path.include?(path)
     end
 
     # MRI: rb_provide_feature