Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pipelining of nameless or non-method-calls #61

Closed
michaelfig opened this issue Oct 1, 2019 · 4 comments
Closed

Pipelining of nameless or non-method-calls #61

michaelfig opened this issue Oct 1, 2019 · 4 comments
Assignees
Labels
eventual-send package: eventual-send marshal package: marshal SwingSet package: SwingSet

Comments

@michaelfig
Copy link
Member

I don't know how to achieve pipelined GETs at the kernel level. I suspect we'll have to define a magic method name, sort of like how x~.(args) (the "nameless invocation") would really invoke a method named __call or something. If x~.foo expanded to E(x).get('foo'), but that turned into a syscall.send(target=x, name='__GET', args=['foo']), then we could probably build something into liveSlots on the receiving end to make it work. But we have to decide how magical of a name we're willing to use, and whether we're willing to tolerate collisions with existing "real" method names.

I would suggest passing something like name=null for each non-method-call kind of operation, and then encode the operation in either the args argument to syscall.send:

  • ['g', 'foo'] get property foo
  • ['s', 'foo', 'bar'] set property foo to bar
  • ['d', 'foo'] delete property foo
  • ['a', ['arg1', 'arg2', 'arg3']] nameless invocation with args

Aside: Fluent Proxy

As far as the E(x) expansion for getters, etc, I don't think we'd pollute the E proxy maker with those concerns. Mark and I discussed having something else, say E.C(x) which would make an unambiguous chainable (i.e. fluent) proxy that could do methods, getters, setters, deleters, and result promises by selecting the operation you want before you invoke it with the name you're interested in.

Something like:

await E.C(x)     // create chainable
  .M.foo('arg1') // method invocation on x, returns chainable for result
  .M('arg1')     // nameless invocation on prior result, returns chainable for result
  .G.foo         // get property foo on prior, returns chainable for value
  .S.foo('bar')  // setter of property foo on prior, returns chainable for 'bar'
  .D[3]          // delete property 3 from prior, returns chainable for boolean
  .P             // extract prior chainable to a Promise

So,

E(x).foo(arg1, arg2)
// is shorthand for:
E.C(x).M.foo(arg1, arg2).P

I will reference this issue when we work out more of the details and put together a proposal for the eventual-send repository.

@warner warner transferred this issue from Agoric/SwingSet Dec 1, 2019
@warner warner added the SwingSet package: SwingSet label Dec 1, 2019
dckc pushed a commit to dckc/agoric-sdk that referenced this issue Dec 5, 2019
R4R: Add environment setting and delete `dep` in `build-run.md`.
dckc pushed a commit to dckc/agoric-sdk that referenced this issue Dec 5, 2019
ERTP with full higher-order composition of smart contracts
dckc pushed a commit to dckc/agoric-sdk that referenced this issue Dec 5, 2019
dckc pushed a commit to dckc/agoric-sdk that referenced this issue Dec 5, 2019
@erights erights added eventual-send package: eventual-send marshal package: marshal labels Apr 19, 2020
@erights
Copy link
Member

erights commented Feb 26, 2021

@michaelfig I think this one is the two of us.

@warner
Copy link
Member

warner commented Sep 27, 2021

@michaelfig and I were talking about something related today (#2691), and I wanted to update a few notes.

  • We don't currently accomodate nameless calls at all, not even non-pipelined
  • I think one step is to teach marshal to accept Far('iface', (arg) => 'result'))
  • userspace will do E(presence)(arg) instead of E(presence).method(arg)
  • It'd also be nice to handle functions-with-function-properties:
const x = (arg1) => 'result';
x.prop1 = (arg2) => 'other result';
return Far('iface', x);
  • so userspace could do both E(p)(arg1) and E(p).prop1(arg2)
  • liveslots will either put a separate handler (apply?) on the HandledPromises it creates, or it will expect to get a prop=null on the existing applyMethod handler when a nameless invocation occurs
  • the syscall.send API needs to accomodate methodname=null, as do the kernel queues and slogfile APIs
  • on the receiving side, liveslots needs to recognize the special methodname and invoke HandledPromise.apply() instead of the current HandledPromise.applyMethod(target, method, args) (unless HP.aM already does the right thing when method=null)
    • liveslots already treats methodname = 'Symbol.asyncIterator' specially, this change would happen in the same place

@erights
Copy link
Member

erights commented Sep 27, 2021

I think one step is to teach marshal to accept Far('iface', (arg) => 'result'))

That part is already done.

@warner
Copy link
Member

warner commented Mar 4, 2022

@Chris-Hibbert mentioned using E(obj)(args) (specifically in contractGovernor.js), and didn't notice any problems. It turns out that local calls work fine (thanks to the HandledPromise support), but remote calls fail.

  • user code does E(obj)(args)
  • HandledPromise calls the applyMethod() handler with prop = undefined (vs usually E(obj).foo(args) causes prop = 'foo')
  • liveslots performs syscall.send(targetSlot, prop, serArgs, resultVPID) from within queueMessage()
  • supervisor-helper.js turns that into an alleged VatSyscallObject (an array) and passes it to doSyscall: doSyscall(['send', target, { method, args, result }])
    • doSyscall applies a function named insistVatSyscallObject() defined in lib/message.js
    • insistVatSyscallObject delegates to insistMessage in the same file
    • insistMessage does assert.typeof(message.method, 'string') and throws when it sees method = undefined
  • this is not caught by anything in supervisor-helper.js and climbs up the stack past queueMessage, terminating the turn that started with applyMethod
  • The E(obj)(args) call returns a Promise which is rejected, with the TypeError: message has non-string .method (an undefined) that came out of insistMessage

So it's not exactly passing silently, but it depends upon someone attaching an error handler to the non-method E()() call to notice.

@Agoric Agoric locked and limited conversation to collaborators May 31, 2022
@michaelfig michaelfig converted this issue into discussion #5478 May 31, 2022

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
eventual-send package: eventual-send marshal package: marshal SwingSet package: SwingSet
Projects
None yet
Development

No branches or pull requests

3 participants