Class: Opal::Rewriters::TargetedPatches

Inherits:
Base
  • Object
show all
Defined in:
lib/opal/rewriters/targeted_patches.rb

Overview

This module attempts to run some optimizations or compatibility improvements against some libraries used with Opal.

This should be a last resort and must not break functionality in existing applications.

Constant Summary

Constants inherited from Base

Base::DUMMY_LOCATION

Instance Attribute Summary

Attributes inherited from Base

#current_node

Instance Method Summary collapse

Methods inherited from Base

#append_to_body, #begin_with_stmts, #dynamic!, #error, #on_top, #prepend_to_body, #process, s, #s, #stmts_of

Instance Method Details

#on_array(node) ⇒ Object



49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/opal/rewriters/targeted_patches.rb', line 49

def on_array(node)
  children = node.children

  # Optimize large arrays produced by lexer, but mainly we are interested
  # in improving compile times, by reducing the tree for the further
  # compilation efforts (also reducing the bundle size a bit)
  #
  # This particular patch reduces compile time of the following command
  # by 12.5%:
  #
  #     OPAL_CACHE_DISABLE=true OPAL_PREFORK_DISABLE=true bin/opal \
  #         --no-source-map -ropal-parser -ropal/platform -ce \
  #         'puts ::Opal.compile($stdin.read)' > _Cnow.js
  #
  # So, in short, an array of a kind:
  #
  #     [1, 2, 3, nil, nil, :something, :abc, nil, ...]
  #
  # Becomes compiled to:
  #
  #     Opal.large_array_unpack("1,2,3,,something,abc,,...")

  if children.length > 32
    ssin_array = children.all? do |child|
      # Break for wrong types
      next false unless %i[str sym int nil].include?(child.type)
      # Break for strings that may conflict with our numbers, nils and separator
      next false if %i[str sym].include?(child.type) && child.children.first.to_s =~ /\A[0-9-]|\A\z|,/
      # Break for too numbers out of range, as there may be decoding issues
      next false if child.type == :int && !(-1_000_000..1_000_000).cover?(child.children.first)
      true
    end

    if ssin_array
      str = children.map { |i| i.children.first.to_s }.join(',')
      node.updated(:jscall, [s(:js_tmp, :Opal), :large_array_unpack, s(:sym, str)])
    else
      super
    end
  else
    super
  end
end

#on_def(node) ⇒ Object



13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/opal/rewriters/targeted_patches.rb', line 13

def on_def(node)
  name, args, body = *node

  if body && body.type == :begin && body.children.length >= 2
    # parser/rubyxx.rb - racc generated code often looks like:
    #
    #     def _reduce_219(val, _values, result)
    #       result = @builder.op_assign(val[0], val[1], val[2])
    #       result
    #     end
    #
    # This converter transform this into just
    #
    #     def _reduce_219(val, _values, result)
    #       @builder.op_assign(val[0], val[1], val[2])
    #     end

    calls = body.children
    assignment, ret = calls.last(2)
    if assignment.type == :lvasgn && ret.type == :lvar &&
       assignment.children.first == ret.children.first

      if calls.length == 2
        node.updated(nil, [name, args, assignment.children[1]])
      else
        calls = calls[0..-3] << assignment.children[1]
        node.updated(nil, [name, args, body.updated(nil, calls)])
      end
    else
      super
    end
  else
    super
  end
end