Skip to content
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

Call stack missing type names on JS in Chrome #11735

Open
justin-espedal opened this issue Jul 27, 2024 · 1 comment
Open

Call stack missing type names on JS in Chrome #11735

justin-espedal opened this issue Jul 27, 2024 · 1 comment

Comments

@justin-espedal
Copy link
Contributor

This seems like a significant oversight, so in addition to reporting this, I'm kinda hoping for a sanity check and maybe some additional historical context from anybody who knows (was this definitely tested before?).

When haxe.CallStack.callStack() is called on the javascript target with ES5 code generation, running in Chrome (or presumably anywhere that V8 is used), any Method stack item that comes from a static or abstract function call will include the type information, but those that come from function calls on an instance of a type will not.

Running the same when ES6 code generation is enabled is even worse. No type names at all are included.

try.haxe program: https://try.haxe.org/#98c971A4

import js.lib.Error;

using StringTools;

class Test {
  static function main() {
    staticFunction();
  }
  
  static function staticFunction()
  {
    var abstractObject = new AbstractObject(new RealObject());
    abstractObject.abstractFunction();
  }
}

abstract AbstractObject(RealObject)
{
  public function new(real:RealObject)
  {
    this = real;
  }

  public function abstractFunction()
  {
    this.instanceFunction();
  }
}

class RealObject
{
  public function new()
  {
    
  }

  public function instanceFunction()
  {
    //js.Syntax.code("debugger");
    var stack = haxe.CallStack.callStack();
    
    for(stackItem in stack)
    {
      trace(stackItem);
    }
    /* ES5
Test.hx:44:,FilePos(Method(null,instanceFunction),_,_,_)
Test.hx:44:,FilePos(Method(AbstractObject,abstractFunction),_,_,_)
Test.hx:44:,FilePos(Method(Test,staticFunction),_,_,_)
Test.hx:44:,FilePos(Method(Test,main),_,_,_)
Test.hx:44:,FilePos(null,_,_,_)
Test.hx:44:,FilePos(null,_,_,_)
    */
    
    /* ES6
Test.hx:44:,FilePos(Method(null,instanceFunction),_,_,_)
Test.hx:44:,FilePos(Method(null,abstractFunction),_,_,_)
Test.hx:44:,FilePos(Method(null,staticFunction),_,_,_)
Test.hx:44:,FilePos(Method(null,main),_,_,_)
Test.hx:44:,FilePos(null,_,_,_)
Test.hx:44:,FilePos(null,_,_,_)
    */
  }
}

This is simple enough to fix in the standard library's javascript implementation of NativeStackTrace.prepareHxStackTrace for ES5 code. I have a commit prepared with a fix for that case (justin-espedal@243c4d9), but thought I'd withhold it pending discussion. For ES6 code I have no idea because site.getTypeName(), site.getFunctionName(), and site.getMethodName() all don't provide the needed information for static functions and abstracts.

@justin-espedal
Copy link
Contributor Author

Okay, I think I see what's going on with ES6.

JavaScript's strict mode is enabled at the top of the program with "use strict";

The V8 stack trace API has this to say about strict mode (https://v8.dev/docs/stack-trace-api):

To maintain restrictions imposed on strict mode functions, frames that have a strict mode function and all frames below (its caller etc.) are not allow to access their receiver and function objects. For those frames, getFunction() and getThis() returns undefined.

site.getTypeName() only returns something useful for instance functions. To use haxe_NativeStackTrace.callStack as an example of a static/abstract function that we can't deal with:

  • site.getTypeName(): Function
  • site.getFunctionName(): callStack
  • site.getMethodName(): callStack
  • site.getThis(): undefined
  • site.getFunction(): undefined
  • site.toString(): 'haxe_NativeStackTrace.callStack (<filename>:<line>:<column>)'

Using the default string encoding of the callsite provides the info we need, but there's no other way to access the type name using the callsite API on ES6 in strict mode. I can only assume that this or function would have provided the information we need if they were available. In this case I guess we should fall back on parsing the default string output of the callstack.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant