CallFrame::thisValue(), CallData::call() for host functions
Hi, First a bit of context: I'm working on using JSC as the backend for Qt Script, the embedded script engine that's part of the Qt application development framework. This means wrapping our existing public API on top of JSC and preserving the semantics to a very large (read: full) extent. So far it's going pretty well, but I'm stumbling upon some issues. If there's another channel I should use for reporting and discussing these things (e.g. the bug tracker), let me know, thanks. Two more issues I've found with host functions: 1) CallFrame::thisValue() crashes for host functions because it goes via codeBlock, which is 0 for host functions. Why does codeBlock need to be used to get the thisRegister, can't it be stored/deduced in the callFrame itself (other places there are calculations like thisRegister = callFrame->registers() - RegisterFile::CallFrameHeaderSize - argCount)? It would be nice if you could get the thisValue() for host function frames too. 2) CallData::call() doesn't create a new frame to execute the host function in. So for instance if you have a host setter function, the setter is going to be executed in the current frame (see JSObject::put()); whereas if a host function is called like a normal function (through the interpreter), it _will_ be executed in a new frame. I've attached a patch where I try to create a new frame in CallData::call(), but it only "almost" seems to work. I copied some code from Interpreter::execute() and the call opcode handler and tried to adapt it. I suspect there's a problem with my calculation of the registerOffset, because the arguments are fetched incorrectly later. Anyone care to comment if I'm on the right track? On a related note, I think there's a bug in op_call for host functions. The scope chain of the caller frame is used as the scope chain of the new frame. This is not consistent with ECMA 10.2.3: "The scope chain is initialised to contain the activation object followed by the objects in the scope chain stored in the [[Scope]] property of the Function object." It's done correctly for JS functions, but not for host functions. It would be nice if host functions could have a [[Scope]] too (i.e. move scope() and setScope() to InternalFunction). Best regards, Kent
On Jan 7, 2009, at 7:30 AM, Kent Hansen wrote:
Hi, First a bit of context: I'm working on using JSC as the backend for Qt Script, the embedded script engine that's part of the Qt application development framework. This means wrapping our existing public API on top of JSC and preserving the semantics to a very large (read: full) extent. So far it's going pretty well, but I'm stumbling upon some issues. If there's another channel I should use for reporting and discussing these things (e.g. the bug tracker), let me know, thanks.
Ah ha, now i understand the context of your previous email, sorry -- yes, for API you will obviously need to at some point talk to JSC internals :D Having a bug filed in http://bugs.webkit.org is best as it makes it easier to scan through archived discussion of each iteration of a patch, and of course it provides a single place where all the versions of the patch can remain for posterity.
Two more issues I've found with host functions: 1) CallFrame::thisValue() crashes for host functions because it goes via codeBlock, which is 0 for host functions. Why does codeBlock need to be used to get the thisRegister, can't it be stored/deduced in the callFrame itself (other places there are calculations like thisRegister = callFrame->registers() - RegisterFile::CallFrameHeaderSize - argCount)? It would be nice if you could get the thisValue() for host function frames too.
The codeblock is used because the position of the this register varies according to whether the code being execute is a global, eval or function code, also when not generating debugging hooks we're not guaranteed to actually provide a correct "this" value
2) CallData::call() doesn't create a new frame to execute the host function in. So for instance if you have a host setter function, the setter is going to be executed in the current frame (see JSObject::put()); whereas if a host function is called like a normal function (through the interpreter), it _will_ be executed in a new frame. I've attached a patch where I try to create a new frame in CallData::call(), but it only "almost" seems to work. I copied some code from Interpreter::execute() and the call opcode handler and tried to adapt it. I suspect there's a problem with my calculation of the registerOffset, because the arguments are fetched incorrectly later. Anyone care to comment if I'm on the right track? Can you give an example of where you think this goes wrong? Host code does not execute on the registerfile, it uses the system stack. If it were to reenter JS execution a new frame will be created at that point.
On a related note, I think there's a bug in op_call for host functions. The scope chain of the caller frame is used as the scope chain of the new frame. This is not consistent with ECMA 10.2.3: "The scope chain is initialised to contain the activation object followed by the objects in the scope chain stored in the [[Scope]] property of the Function object." It's done correctly for JS functions, but not for host functions. It would be nice if host functions could have a [[Scope]] too (i.e. move scope() and setScope() to InternalFunction).
Once again I'm not sure what you're referring to here, the host functions are not defined in JS, so by definition they will not be using the JS scope chain. --Oliver
Whoops, I forgot to say: we also hang around on #squirrelfish on freenode should you wish to discuss stuff there --Oliver
participants (2)
-
Kent Hansen
-
Oliver Hunt