Skip to content

Commit

Permalink
Merge pull request #1909 from opal/elia/allocate-a-class-object-for-b…
Browse files Browse the repository at this point in the history
…ridged-classes

Allocate a class object for bridged classes
  • Loading branch information
elia committed Dec 30, 2018
2 parents ca4816c + a1c0503 commit 2a5059b
Show file tree
Hide file tree
Showing 26 changed files with 161 additions and 151 deletions.
8 changes: 8 additions & 0 deletions bin/setup
@@ -0,0 +1,8 @@
#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'
set -vx

bundle update

git submodule update --init
22 changes: 15 additions & 7 deletions lib/opal/nodes/base.rb
Expand Up @@ -165,17 +165,25 @@ def in_ensure?
scope.in_ensure?
end

def closest_module_node
current = scope
while current && !current.class_scope?
current = current.parent
def class_variable_owner_nesting_level
cvar_scope = scope
nesting_level = 0

while cvar_scope && !cvar_scope.class_scope?
# Needs only `class << self`, `module`, and `class`
# can increase nesting, but `class` & `module` are
# covered by `class_scope?`.
nesting_level += 1 if cvar_scope.sclass?

cvar_scope = cvar_scope.parent
end
current

nesting_level
end

def class_variable_owner
if closest_module_node
"$#{closest_module_node.name}"
if scope
"$nesting[#{class_variable_owner_nesting_level}]"
else
'Opal.Object'
end
Expand Down
4 changes: 1 addition & 3 deletions lib/opal/nodes/class.rb
Expand Up @@ -14,12 +14,10 @@ def compile
helper :klass

push '(function($base, $super, $parent_nesting) {'
line " function $#{name}(){};"
line " var self = $#{name} = $klass($base, $super, '#{name}', $#{name});"
line " var self = $klass($base, $super, '#{name}');"

in_scope do
scope.name = name
add_temp "#{scope.proto} = self.prototype"
add_temp '$nesting = [self].concat($parent_nesting)'

body_code = self.body_code
Expand Down
4 changes: 1 addition & 3 deletions lib/opal/nodes/module.rb
Expand Up @@ -14,12 +14,10 @@ def compile
helper :module

push '(function($base, $parent_nesting) {'
line " function $#{name}() {};"
line " var self = $#{name} = $module($base, '#{name}', $#{name});"
line " var self = $module($base, '#{name}');"

in_scope do
scope.name = name
add_temp "#{scope.proto} = self.prototype"
add_temp '$nesting = [self].concat($parent_nesting)'

body_code = stmt(body || s(:nil))
Expand Down
10 changes: 1 addition & 9 deletions lib/opal/nodes/scope.rb
Expand Up @@ -108,13 +108,6 @@ def def_in_class?
!@defs && @type == :def && @parent && @parent.class?
end

# Inside a class or module scope, the javascript variable name returned
# by this function points to the classes' prototype. This is the target
# to where methods are actually added inside a class body.
def proto
'def'
end

##
# Vars to use inside each scope
def to_vars
Expand All @@ -135,8 +128,7 @@ def to_vars
str += "#{indent}#{gv.join indent}" unless gvars.empty?

if class? && !@proto_ivars.empty?
# raise "FIXME to_vars"
pvars = @proto_ivars.map { |i| "#{proto}#{i}" }.join(' = ')
pvars = @proto_ivars.map { |i| "self.$$prototype#{i}" }.join(' = ')
result = "#{str}\n#{indent}#{pvars} = nil;"
else
result = str
Expand Down
1 change: 0 additions & 1 deletion lib/opal/nodes/singleton_class.rb
Expand Up @@ -13,7 +13,6 @@ def compile
push '(function(self, $parent_nesting) {'

in_scope do
add_temp 'def = self.prototype'
add_temp '$nesting = [self].concat($parent_nesting)'

body_stmt = stmt(compiler.returns(body))
Expand Down
3 changes: 1 addition & 2 deletions lib/opal/nodes/super.rb
Expand Up @@ -73,8 +73,7 @@ def def_scope_identity

def super_method_invocation
if def_scope.defs
class_name = def_scope.parent.name ? "$#{def_scope.parent.name}" : 'self.$$class.prototype'
"Opal.find_super_dispatcher(self, '#{method_id}', #{def_scope_identity}, #{defined_check_param}, #{class_name})"
"Opal.find_super_dispatcher(self, '#{method_id}', #{def_scope_identity}, #{defined_check_param}, self.$$class.$$prototype)"
else
"Opal.find_super_dispatcher(self, '#{method_id}', #{def_scope_identity}, #{defined_check_param})"
end
Expand Down
8 changes: 4 additions & 4 deletions opal/corelib/array.rb
Expand Up @@ -5,7 +5,7 @@ class Array < `Array`
include Enumerable

# Mark all javascript arrays as being valid ruby arrays
`Opal.defineProperty(Array.prototype, '$$is_array', true)`
`Opal.defineProperty(self.$$prototype, '$$is_array', true)`

%x{
function toArraySubclass(obj, klass) {
Expand Down Expand Up @@ -237,9 +237,9 @@ def ==(other)
}
}
if (array.constructor !== Array)
if (array.$$constructor !== Array)
array = #{`array`.to_a};
if (other.constructor !== Array)
if (other.$$constructor !== Array)
other = #{`other`.to_a};
if (array.length !== other.length) {
Expand Down Expand Up @@ -2334,7 +2334,7 @@ def zip(*others, &block)

def self.inherited(klass)
%x{
klass.prototype.$to_a = function() {
klass.$$prototype.$to_a = function() {
return this.slice(0, this.length);
}
}
Expand Down
4 changes: 2 additions & 2 deletions opal/corelib/boolean.rb
@@ -1,6 +1,6 @@
class Boolean < `Boolean`
`Opal.defineProperty(Boolean.prototype, '$$is_boolean', true)`
`Opal.defineProperty(Boolean.prototype, '$$meta', #{self})`
`Opal.defineProperty(self.$$prototype, '$$is_boolean', true)`
`Opal.defineProperty(self.$$prototype, '$$meta', #{self})`

class << self
def allocate
Expand Down
4 changes: 2 additions & 2 deletions opal/corelib/class.rb
Expand Up @@ -7,7 +7,7 @@ def self.new(superclass = Object, &block)
throw Opal.TypeError.$new("superclass must be a Class");
}
var klass = Opal.allocate_class(nil, superclass, function(){});
var klass = Opal.allocate_class(nil, superclass);
superclass.$inherited(klass);
#{`klass`.class_eval(&block) if block_given?}
return klass;
Expand All @@ -16,7 +16,7 @@ def self.new(superclass = Object, &block)

def allocate
%x{
var obj = new self();
var obj = new self.$$constructor();
obj.$$id = Opal.uid();
return obj;
}
Expand Down
2 changes: 1 addition & 1 deletion opal/corelib/enumerator.rb
Expand Up @@ -3,7 +3,7 @@
class Enumerator
include Enumerable

`def.$$is_enumerator = true`
`self.$$prototype.$$is_enumerator = true`

def self.for(object, method = :each, *args, &block)
%x{
Expand Down
2 changes: 1 addition & 1 deletion opal/corelib/error.rb
Expand Up @@ -5,7 +5,7 @@ class Exception < `Error`
def self.new(*args)
%x{
var message = (args.length > 0) ? args[0] : nil;
var error = new self(message);
var error = new self.$$constructor(message);
error.name = self.$$name;
error.message = message;
Opal.send(error, error.$initialize, args);
Expand Down
4 changes: 2 additions & 2 deletions opal/corelib/hash.rb
Expand Up @@ -12,7 +12,7 @@ class Hash
include Enumerable

# Mark all hash instances as valid hashes (used to check keyword args, etc)
`def.$$is_hash = true`
`self.$$prototype.$$is_hash = true`

def self.[](*argv)
%x{
Expand Down Expand Up @@ -65,7 +65,7 @@ def self.[](*argv)

def self.allocate
%x{
var hash = new self();
var hash = new self.$$constructor();
Opal.hash_init(hash);
Expand Down
2 changes: 1 addition & 1 deletion opal/corelib/helpers.rb
Expand Up @@ -155,7 +155,7 @@ def self.pristine(owner_class, *method_names)
var method_name, method;
for (var i = method_names.length - 1; i >= 0; i--) {
method_name = method_names[i];
method = owner_class.prototype['$'+method_name];
method = owner_class.$$prototype['$'+method_name];
if (method && !method.$$stub) {
method.$$pristine = true;
Expand Down
8 changes: 4 additions & 4 deletions opal/corelib/kernel.rb
Expand Up @@ -118,19 +118,19 @@ def copy_singleton_methods(other)
if (other.hasOwnProperty('$$meta')) {
var other_singleton_class = Opal.get_singleton_class(other);
var self_singleton_class = Opal.get_singleton_class(self);
names = Object.getOwnPropertyNames(other_singleton_class.prototype);
names = Object.getOwnPropertyNames(other_singleton_class.$$prototype);
for (i = 0, length = names.length; i < length; i++) {
name = names[i];
if (Opal.is_method(name)) {
self_singleton_class.prototype[name] = other_singleton_class.prototype[name];
self_singleton_class.$$prototype[name] = other_singleton_class.$$prototype[name];
}
}
self_singleton_class.$$const = Object.assign({}, other_singleton_class.$$const);
Object.setPrototypeOf(
self_singleton_class.prototype,
Object.getPrototypeOf(other_singleton_class.prototype)
self_singleton_class.$$prototype,
Object.getPrototypeOf(other_singleton_class.$$prototype)
);
}
Expand Down
12 changes: 6 additions & 6 deletions opal/corelib/module.rb
Expand Up @@ -3,7 +3,7 @@ def self.allocate
%x{
var module = Opal.allocate_module(nil, function(){});
// Link the prototype of Module subclasses
if (self !== Opal.Module) Object.setPrototypeOf(module, self.prototype);
if (self !== Opal.Module) Object.setPrototypeOf(module, self.$$prototype);
return module;
}
end
Expand Down Expand Up @@ -111,7 +111,7 @@ def attr_accessor(*names)

def attr_reader(*names)
%x{
var proto = self.prototype;
var proto = self.$$prototype;
for (var i = names.length - 1; i >= 0; i--) {
var name = names[i],
Expand Down Expand Up @@ -146,7 +146,7 @@ def attr_reader(*names)

def attr_writer(*names)
%x{
var proto = self.prototype;
var proto = self.$$prototype;
for (var i = names.length - 1; i >= 0; i--) {
var name = names[i],
Expand Down Expand Up @@ -431,7 +431,7 @@ def include?(mod)

def instance_method(name)
%x{
var meth = self.prototype['$' + name];
var meth = self.$$prototype['$' + name];
if (!meth || meth.$$stub) {
#{raise NameError.new("undefined method `#{name}' for class `#{self.name}'", name)};
Expand Down Expand Up @@ -523,7 +523,7 @@ def module_exec(*args, &block)

def method_defined?(method)
%x{
var body = self.prototype['$' + method];
var body = self.$$prototype['$' + method];
return (!!body) && !body.$$stub;
}
end
Expand All @@ -537,7 +537,7 @@ def module_function(*methods)
for (var i = 0, length = methods.length; i < length; i++) {
var meth = methods[i],
id = '$' + meth,
func = self.prototype[id];
func = self.$$prototype[id];
Opal.defs(self, id, func);
}
Expand Down
2 changes: 1 addition & 1 deletion opal/corelib/nil.rb
@@ -1,5 +1,5 @@
class NilClass
`def.$$meta = #{self}`
`self.$$prototype.$$meta = #{self}`

class << self
def allocate
Expand Down
2 changes: 1 addition & 1 deletion opal/corelib/number.rb
Expand Up @@ -2,7 +2,7 @@

class Number < Numeric
Opal.bridge(`Number`, self)
`Opal.defineProperty(Number.prototype, '$$is_number', true)`
`Opal.defineProperty(self.$$prototype, '$$is_number', true)`
`self.$$is_number_class = true`

class << self
Expand Down
4 changes: 2 additions & 2 deletions opal/corelib/proc.rb
@@ -1,6 +1,6 @@
class Proc < `Function`
`Opal.defineProperty(Function.prototype, '$$is_proc', true)`
`Opal.defineProperty(Function.prototype, '$$is_lambda', false)`
`Opal.defineProperty(self.$$prototype, '$$is_proc', true)`
`Opal.defineProperty(self.$$prototype, '$$is_lambda', false)`

def self.new(&block)
unless block
Expand Down
2 changes: 1 addition & 1 deletion opal/corelib/range.rb
Expand Up @@ -3,7 +3,7 @@
class Range
include Enumerable

`def.$$is_range = true`
`self.$$prototype.$$is_range = true`

attr_reader :begin, :end

Expand Down
2 changes: 1 addition & 1 deletion opal/corelib/regexp.rb
Expand Up @@ -5,7 +5,7 @@ class Regexp < `RegExp`
EXTENDED = 2
MULTILINE = 4

`Opal.defineProperty(RegExp.prototype, '$$is_regexp', true)`
`Opal.defineProperty(self.$$prototype, '$$is_regexp', true)`

class << self
def allocate
Expand Down

0 comments on commit 2a5059b

Please sign in to comment.