Permalink
Browse files

handle Rhino's 64K code generation (method) limit on the fly

simple retry running the failed compilation in interpreter mode
  • Loading branch information...
1 parent 23c6173 commit 05ece36c5d598460273cb88dcceb009e6145f657 @kares kares committed Dec 5, 2012
Showing with 55 additions and 8 deletions.
  1. +40 −8 lib/rhino/context.rb
  2. +15 −0 spec/rhino/context_spec.rb
View
@@ -240,24 +240,56 @@ def javascript_version=(version)
alias :version= :javascript_version=
# Enter this context for operations.
- # Some methods such as eval() will fail unless this context is open !
+ # Some methods such as eval() will fail unless the context is open.
def open(&block)
do_open(&block)
rescue JS::RhinoException => e
+ if code_generation_error?(e)
+ warn "[INFO] Rhino byte-code generation failed forcing #{@native} into interpreted mode"
+ self.optimization_level = -1
+ retry
+ end
raise Rhino::JSError.new(e)
end
private
- def do_open
- factory.enterContext(@native)
- begin
- yield self
- ensure
- factory.exit
- end
+ def do_open # :nodoc
+ factory.enterContext(@native)
+ begin
+ yield self
+ ensure
+ factory.exit
end
+ end
+ CODE_GENERATION_ERROR_MESSAGE = 'generated bytecode for method exceeds 64K limit' # :nodoc
+
+ CODE_GENERATION_TRACE_CLASS_NAME = 'org.mozilla.javascript.optimizer.Codegen' # :nodoc
+ CODE_GENERATION_TRACE_METHOD_NAME = 'reportClassFileFormatException' # :nodoc
+ # at org.mozilla.javascript.optimizer.Codegen.reportClassFileFormatException
+
+ def code_generation_error?(exception) # :nodoc
+ if ( exception.is_a?(NativeException) rescue nil ) # JRuby 1.6 wrapping
+ exception = exception.cause
+ end
+ if exception.class == Rhino::JS::EvaluatorException
+ if exception.message.index(CODE_GENERATION_ERROR_MESSAGE)
+ return true
+ end
+ # NOTE: unfortunately Rhino localizes the error messages!
+ # and the ClassFileFormatException is not kept as a cause
+ class_name = CODE_GENERATION_TRACE_CLASS_NAME
+ method_name = CODE_GENERATION_TRACE_METHOD_NAME
+ for trace in exception.getStackTrace()
+ if class_name == trace.class_name && method_name == trace.method_name
+ return true
+ end
+ end
+ end
+ false
+ end
+
end
class IOReader < java.io.Reader # :nodoc:
View
@@ -166,4 +166,19 @@ def foo(*args); args && 'bar'; end
end
end
+ it "handles code generation error when 'generated bytecode for method exceeds 64K limit'" do
+ context = Rhino::Context.new
+
+ big_script = ''
+ 10000.times { |i| big_script << "var s#{i} = '#{i}';\n" }
+ 10000.times { |i| big_script << "var n#{i} = +#{i} ;\n" }
+
+ lambda {
+ context.eval big_script
+ }.should_not raise_error
+
+ context.eval('( s9999 )').should == '9999'
+ context.eval('( n9999 )').should == +9999
+ end
+
end

0 comments on commit 05ece36

Please sign in to comment.