How does MRI parse the ||= operator?

Hi,
I posted this question on stack overflow and I was wondering if anyone on this list might have some insight into it.
Basically I'm trying to understand how Ruby handles the `||=` operator and trying to understand where exactly the thread scheduler is allowed to switch contexts which in turn makes the `||=` operator non-thread safe.
I tried starting at the code in parse.y and following `tOROP` but I got lost pretty quickly. I was hoping someone here might be able to explain the parsing process to me in a little more depth so that if I ever question if some built-in is thread safe or not then I can just look at the source

Thanks,
Josh

You don't want to look at the parse code. Trust me. Look at the instructions generated for your code example. Check out this fantastic article for some insights: How Ruby Executes Your Code - Pat Shaughnessy

···

On Sep 10, 2015, at 11:43, Joshua Bodah <jb3689@yahoo.com> wrote:

Hi,

I posted this question on stack overflow and I was wondering if anyone on this list might have some insight into it.

Basically I'm trying to understand how Ruby handles the `||=` operator and trying to understand where exactly the thread scheduler is allowed to switch contexts which in turn makes the `||=` operator non-thread safe.

I tried starting at the code in parse.y and following `tOROP` but I got lost pretty quickly. I was hoping someone here might be able to explain the parsing process to me in a little more depth so that if I ever question if some built-in is thread safe or not then I can just look at the source

Also, in short:

    a ||= b

is like:

    a || (a = b)

So there are spots in there where threads can interject.

···

On 11/09/2015 7:27 AM, "Ryan Davis" <ryand-ruby@zenspider.com> wrote:

> On Sep 10, 2015, at 11:43, Joshua Bodah <jb3689@yahoo.com> wrote:
>
> Hi,
>
> I posted this question on stack overflow and I was wondering if anyone
on this list might have some insight into it.
>
> Basically I'm trying to understand how Ruby handles the `||=` operator
and trying to understand where exactly the thread scheduler is allowed to
switch contexts which in turn makes the `||=` operator non-thread safe.
>
> I tried starting at the code in parse.y and following `tOROP` but I got
lost pretty quickly. I was hoping someone here might be able to explain the
parsing process to me in a little more depth so that if I ever question if
some built-in is thread safe or not then I can just look at the source

You don't want to look at the parse code. Trust me. Look at the
instructions generated for your code example. Check out this fantastic
article for some insights:
How Ruby Executes Your Code - Pat Shaughnessy

Thanks for the response. I've read a couple of Pat's posts and they've been really helpful for understanding the concepts, but I haven't been able to find too much of an actual walkthrough. It looks like Pat posted short walkthrough here: A Simple Tour of the Ruby MRI Source Code with Pat Shaughnessy
I guess the real underlying question I have is about the GIL. I'm trying to find what in the source makes the ||= operator not thread-safe. Does the GIL wraps the execution of each individual YARV instruction or does the GIL work on a higher level than that (i.e. GIL locks over execution of multiple YARV instructions)?
Josh

···

From: Matthew Kerwin <matthew@kerwin.net.au>
To: ruby-talk ML <ruby-talk@ruby-lang.org>
Sent: Thursday, September 10, 2015 5:50 PM
Subject: Re: How does MRI parse the ||= operator?
   
Also, in short: a ||= bis like: a || (a = b)So there are spots in there where threads can interject.On 11/09/2015 7:27 AM, "Ryan Davis" <ryand-ruby@zenspider.com> wrote:

On Sep 10, 2015, at 11:43, Joshua Bodah <jb3689@yahoo.com> wrote:

Hi,

I posted this question on stack overflow and I was wondering if anyone on this list might have some insight into it.

Basically I'm trying to understand how Ruby handles the `||=` operator and trying to understand where exactly the thread scheduler is allowed to switch contexts which in turn makes the `||=` operator non-thread safe.

I tried starting at the code in parse.y and following `tOROP` but I got lost pretty quickly. I was hoping someone here might be able to explain the parsing process to me in a little more depth so that if I ever question if some built-in is thread safe or not then I can just look at the source

You don't want to look at the parse code. Trust me. Look at the instructions generated for your code example. Check out this fantastic article for some insights: How Ruby Executes Your Code - Pat Shaughnessy

Rather as a:

    a = b if respond_to?(:a) && !a.nil?

···

--
Łukasz Niemier <lukasz@niemier.pl>
http://lukasz.niemier.pl

2015-09-10 23:50 GMT+02:00 Matthew Kerwin <matthew@kerwin.net.au>:

Also, in short:

    a ||= b

is like:

    a || (a = b)

So there are spots in there where threads can interject.
On 11/09/2015 7:27 AM, "Ryan Davis" <ryand-ruby@zenspider.com> wrote:

> On Sep 10, 2015, at 11:43, Joshua Bodah <jb3689@yahoo.com> wrote:
>
> Hi,
>
> I posted this question on stack overflow and I was wondering if anyone
on this list might have some insight into it.
>
> Basically I'm trying to understand how Ruby handles the `||=` operator
and trying to understand where exactly the thread scheduler is allowed to
switch contexts which in turn makes the `||=` operator non-thread safe.
>
> I tried starting at the code in parse.y and following `tOROP` but I got
lost pretty quickly. I was hoping someone here might be able to explain the
parsing process to me in a little more depth so that if I ever question if
some built-in is thread safe or not then I can just look at the source

You don't want to look at the parse code. Trust me. Look at the
instructions generated for your code example. Check out this fantastic
article for some insights:
How Ruby Executes Your Code - Pat Shaughnessy

I think that the relevant part is in compile.c:

case NODE_OP_ASGN_AND:
case NODE_OP_ASGN_OR:{
  LABEL *lfin = NEW_LABEL(line);
  LABEL *lassign;

  if (nd_type(node) == NODE_OP_ASGN_OR) {
      LABEL *lfinish[2];
      lfinish[0] = lfin;
      lfinish[1] = 0;
      defined_expr(iseq, ret, node->nd_head, lfinish, Qfalse);
      lassign = lfinish[1];
      if (!lassign) {
          lassign = NEW_LABEL(line);
      }
      ADD_INSNL(ret, line, branchunless, lassign);
  }
  else {
      lassign = NEW_LABEL(line);
  }

  COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_head", node->nd_head);
  ADD_INSN(ret, line, dup);

  if (nd_type(node) == NODE_OP_ASGN_AND) {
      ADD_INSNL(ret, line, branchunless, lfin);
  }
  else {
      ADD_INSNL(ret, line, branchif, lfin);
  }

  ADD_INSN(ret, line, pop);
  ADD_LABEL(ret, lassign);
  COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_value", node->nd_value);
  ADD_LABEL(ret, lfin);

  if (poped) {
      /* we can apply more optimize */
      ADD_INSN(ret, line, pop);
  }
  break;
}

I'm having trouble translating it to a sequence of VM instructions. Anyone?

Best regards
Greg Navis

···

On Fri, Sep 11, 2015 at 1:58 PM, Łukasz Niemier <lukasz@niemier.pl> wrote:

Rather as a:

    a = b if respond_to?(:a) && !a.nil?

--
Łukasz Niemier <lukasz@niemier.pl>
http://lukasz.niemier.pl

2015-09-10 23:50 GMT+02:00 Matthew Kerwin <matthew@kerwin.net.au>:

Also, in short:

    a ||= b

is like:

    a || (a = b)

So there are spots in there where threads can interject.
On 11/09/2015 7:27 AM, "Ryan Davis" <ryand-ruby@zenspider.com> wrote:

> On Sep 10, 2015, at 11:43, Joshua Bodah <jb3689@yahoo.com> wrote:
>
> Hi,
>
> I posted this question on stack overflow and I was wondering if anyone
on this list might have some insight into it.
>
> Basically I'm trying to understand how Ruby handles the `||=` operator
and trying to understand where exactly the thread scheduler is allowed to
switch contexts which in turn makes the `||=` operator non-thread safe.
>
> I tried starting at the code in parse.y and following `tOROP` but I
got lost pretty quickly. I was hoping someone here might be able to explain
the parsing process to me in a little more depth so that if I ever question
if some built-in is thread safe or not then I can just look at the source

You don't want to look at the parse code. Trust me. Look at the
instructions generated for your code example. Check out this fantastic
article for some insights:
http://patshaughnessy.net/2012/6/29/how-ruby-executes-your-code