mirror of
https://github.com/rubyjs/therubyrhino
synced 2023-03-27 23:21:34 -04:00
handle Rhino's 64K code generation (method) limit on the fly
simple retry running the failed compilation in interpreter mode
This commit is contained in:
parent
23c617345e
commit
05ece36c5d
2 changed files with 55 additions and 8 deletions
|
@ -240,24 +240,56 @@ module Rhino
|
||||||
alias :version= :javascript_version=
|
alias :version= :javascript_version=
|
||||||
|
|
||||||
# Enter this context for operations.
|
# 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)
|
def open(&block)
|
||||||
do_open(&block)
|
do_open(&block)
|
||||||
rescue JS::RhinoException => e
|
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)
|
raise Rhino::JSError.new(e)
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def do_open
|
def do_open # :nodoc
|
||||||
factory.enterContext(@native)
|
factory.enterContext(@native)
|
||||||
begin
|
begin
|
||||||
yield self
|
yield self
|
||||||
ensure
|
ensure
|
||||||
factory.exit
|
factory.exit
|
||||||
end
|
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
class IOReader < java.io.Reader # :nodoc:
|
class IOReader < java.io.Reader # :nodoc:
|
||||||
|
|
|
@ -166,4 +166,19 @@ describe Rhino::Context do
|
||||||
end
|
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
|
end
|
Loading…
Reference in a new issue