Saturday, December 24, 2016

Node js C++ Addon Overload Resolution - Update

Since the last update on December 13th, multiple enhancements have been made, So far I'm happy!

Major changes and improvements:


  • The major performance issue in the tests have been found, when many overloads are added, the engine goes over all of them to find the most suitable one, this takes time and CPU. The first part that needs optimization is probably the determineType function.
  • make_param added overloads and template type specialization for multiple types, which makes the overload creation simpler and more robust.
  • Automatic async function implementation is now simple and straight forward, as long as only c++ typed templated functions are used for This<T> and at<T> (replaces info[]) and SetReturnValue<T>, the function should be able to run async, just note that async functions are executed in libuv's threadpool, which means you'll have to handle locks manually or use thread safe function calls. With locks comes great responsibility, node js libuv threadpool default size is 4 threads, too many waiting threads will either kill or slow down node js significantly.
  • Accessing This, info[] and GetReturnValue will now throw an exception if attempted execution in async, no more crashes if these calls were made by mistake, just a normal v8 exception.
  • Partial logging for what happens in the engine, TRACE for function calls, DEBUG for diagnostics, WARN for something that's not as designed and ERROR for usage mistakes.

Monday, December 19, 2016

Node js Addon Logger Module

One of the issues I'm attempting to solve while programming node js addons is logging. I've looked for solutions for some time but there's no way to communicate to v8 the addon's internal logs. so I'm left with a few options which are not completely satisfactory. 

Dump the logs to console

I can dump the logs to the console but how do I redirect them to a file? if I redirect the entire stderr or stdout, I'll have irrelevant log entries in my log and trying to split them by module name could be useless work I'll need to do later.

Dump the logs to file

Dumping the logs to a log file is probably the easiest solution, I could use something like log4cpp or Pantheios, but importing them into a node addon could add a whole other set of problems, like how to set the appender at runtime and how do I manage modules, but Pantheios is claimed to be one of the fastest frameworks by their own benchmarks.

Eventually I've decided to try to POC my own with node js domain in mind, its not the best, but its good enough (tm), at least for now.


The basic requirements are:

- must support multithreaded logging
- must be easy on the v8 engine, e.g don't freeze the VM.
- must be able to filter out unneeded log levels, so debug/trace in debug sessons and info and above for production.
- optional - communicate with v8 the log messages

So I went ahead and planned it, its not too complicated, we have only two components at the moment, a queue for holding the debug messages between flushes and a notifier to v8 that there are pending log messages to be processed.


At the moment the queue is a quick write of locking std::queue implemented with std::lock_guard<std::mutex> with an atomic counter to keep track of the number of messages in the queue.


the notifier is implemented as libuv uv_async_send api, which basically schedules an async to be executed on the main node js thread.


on top of it I've added the following APIs exposed to node:


RegisterLogger - to register log callbacks, this way node js can use log4js and do everything in one place, not very efficient, but again, good enough for now.


Flush - which forces the callback to execute and flush any pending log messages

log_level property - to control what to log, so if we set this on Error but a Debug message comes in, the logger will ignore it.

batch_length property - how many log messages to process in one main thread event loop iteration, reducing it will make the log slower but the vm will be more responsive, increasing it may cause the vm to freeze when many log messages are being returned back to v8.


and of curse Log - which can be used for testing purposes or anything else, just don't use it for actual logging as the round trip from v8 -> c++ -> v8 is a waste of perfectly good cpu and memory resources.


Issues:

- Performance, which could be improved by using a better lock-free queue or perhaps even using a queue per thread as node js is essentially threadpooled. perhaps the callback can accept an array of log messages saving the round trip time between v8 and c++.

- Separation of logs, currently all log messages go in the same queue, so when your callback is getting called, its getting all the messages. 


- One callback only, no support for multiple callbacks


- Queue is only increasing in size, its not a memory leak, but if you don't flush your callback every once in a while, it might look like one. std::queue does not implement shrink_to_fit, so the only way to flush it is to create a new one and swap them.


- Log messages might get lost when the vm crashes, since all logging is done in memory, if the vm crashes without the logs being purged, the messages will be lost to the gods of memory dumps.


This module is a start, I'll probably improve it as the needs grow/change.


You can find the project here:

https://github.com/drorgl/node-addon-tracer

What's next? Perhaps an instrumentation module... :-)

Tuesday, December 13, 2016

Node js C++ Addon Overload Resolution - Refactor & Add C++ Type Converter

Remember node-overload-resolution ?

I've been working on it for a while to see how I can support automatic async support.

I always believed if you can work a little harder to save a lot of time later, its most likely going to pay off, one of the biggest motivation to write the node-overload-resolution project was to easily convert C++ libraries to Node js without changing the API too much.

One of the major roadblocks in the last version of node-overload-resolution to this goal is that v8 objects are not accessible through any other thread other than node js main thread since node doesn't release the locker on v8 vm. To solve this issue I thought and implemented a way to parse and store the v8 objects as their projected C++ objects. in essence copying v8::String to std::string, v8::Number to double and so on.

Some issues I've encountered with this approach is how to store v8 Objects, C++ Class wrappers and Arrays, but if I can actually tell the resolution module which C++ types each v8 type translates to, maybe it could work.

I've been working on this premise and implemented a converter and value holder on top of the working overload resolution module and currently it supports Number, Function, String, Buffer, a typed struct and ObjectWrap.

Currently there are issues with Function, its implemented as or::Callback, but the actual function is not called yet.

Other issues is that I couldn't find a translation for Promise, Proxy and RegExp.

I think this module is on the correct path at the moment, it should be relatively easy to support async function calls by adding a check if the matched function have an additional function callback parameter, caching the parameter value as C++ type, pushing the function call to libuv threadpool and executing the return value conversion and callbacks activation when the thread finishes execution.

You can find the code on the native_types branch.

The code is concentrated in 3 main components, the value_holder, the value_converter and the generic_value_holder. 

The value_holder is a derived template, storing the Value inside a template type.

template<typename T>
class value_holder : public value_holder_base {
public:
    T Value;
    value_holder() : value_holder_base() {}
    value_holder(T val) : value_holder_base(), Value(val) {}
    virtual ~value_holder() {}
};



The value_converter is a derived template with template specialization for each major type handled, the specialization is both for primitives (including v8 basic types) and for derived classes for IStructuredObject and ObjectWrap classes, allowing a more specific behavior for structures and C++ classes, such as parsing/creating new v8 objects as well as ObjectWrap::Wrap and ObjectWrap::Unwrap.

for example, this template specialization is for all derived classes of ObjectWrap, it wraps/unwraps to/from v8::Object:
template<typename T>
class value_converter<T*, typename std::enable_if<std::is_base_of<ObjectWrap, T>::value>::type> : publicvalue_converter_base {
public:

    virtual T* convert(v8::Local<v8::Value> from) {
        return or::ObjectWrap::Unwrap<T>(from.As<v8::Object>());
    }


    virtual v8::Local<v8::Value> convert(T* from) {
        return from->Wrap();
    }

    virtual v8::Local<v8::Value> convert(std::shared_ptr<value_holder_base> from) {
        auto from_value = std::dynamic_pointer_cast<value_holder<T*>>(from);
        return from_value->Value->Wrap();
    }

    virtual std::shared_ptr<value_holder_base> read(v8::Local<v8::Value> val) {
        auto parsed_value = std::make_shared<value_holder<T*>>();
        parsed_value->Value = convert(val);
        return parsed_value;
    }

};

lastly the generic_value_holder stores a pair of value_holder and value_converter and by that it can act as some sort of non-convertible variant that can return a v8 object from intended C++ types.

class generic_value_holder {
private:
    std::shared_ptr< or ::value_converter_base> _prefetcher;
    std::shared_ptr< or ::value_holder_base> _value;
public:
    void Set(std::shared_ptr< or ::value_converter_base> value_converter, std::shared_ptr< or ::value_holder_base> value) {
        _prefetcher = value_converter;
        _value = value;
    }

    template<typename T>
    void Set(T returnValue) {
        //store value_converter type
        auto returnPrefetcher = std::make_shared < or ::value_converter<T>>();

        //store value inside a valueholder
        auto valueHolder = std::make_shared < or ::value_holder<T>>();
        valueHolder->Value = returnValue;

        Set(returnPrefetcher, valueHolder);
    }

    v8::Local<v8::Value> Get() {
        return _prefetcher->convert(_value);
    }
};

Update 2016-12-14:
The automatic async has been partially implemented, at this moment, the tests are working as far as I can see. what happens is that the overload resolution is checking the last argument passed to the function, if its not part of the function parameters and its type is a function, its assumed to be an async request. so the overload resolution engine stores all the function arguments in memory as C++ objects, calls the function and post process the return value and lastly calls the callback function supplied.

for example, assuming you have a function test(arg1 : string, arg2 : number), if a match is found that contains test("a",1), it will execute the function synchronously. But if a match is found as test("a",1,function(err,val){}), it will be executed asynchronously (note that there is no way to know which parameters are defined for function(err,val), so the example above is for clarity sake.

The functions implementation have to use info.at<T>(index) to read the parameters and have to use info.SetReturnValue<T>(value) to return a value, otherwise the implementation will fail because node js keeps the vm locked and there's no access to v8 objects through normal info[index] mechanism, if the implementer insists on using info[index], an access violation will occur and the application will crash when executing as async.

TODO:
- Finish the callback implementation.
- Implement Async call detection and execution - partial.
- This() access from inside a class member function
- cleanup

Wednesday, November 30, 2016

Async in Node.js Addons with NAN

Async in node js is implemented as threadpool jobs. The way node js works is that V8 is executed in the main thread, when V8 needs to call a c++ function it can either execute it in the main thread or it can schedule it in the threadpool.

Node js uses libuv asynchronous I/O library. by default it uses 4 threads in the threadpool, but it can be changed with the UV_THREADPOOL_SIZE environment variable. (ref)

The way NAN async works is, first you define a c++ class (which inherits from AsyncWorker or that accepts a callback and c++ primitive data types as parameters. then you define the Execute function which does the actual work and lastly you define the HandleOKCallback function which will do the actual callback.

The first step is to create a Nan::Callback instance from the v8::Function parameter, which is a standard Javascript error-first callback, which later can be converted to Promises.


// Asynchronous access to the `Estimate()` function
NAN_METHOD(CalculateAsync) {
  int points = To<int>(info[0]).FromJust();
  Callback *callback = new Callback(info[1].As<Function>());

  AsyncQueueWorker(new PiWorker(callback, points));
}

If you need to keep data between the call and the callback you can use SaveToPersistent and GetFromPersistent, this data is not available inside the async execution but its only used between the Callback instantiation and the javascript callback after execution.

From v8 Embedder's Guide:

Persistent handles provide a reference to a heap-allocated JavaScript Object, just like a local handle. There are two flavors, which differ in the lifetime management of the reference they handle. Use a persistent handle when you need to keep a reference to an object for more than one function call, or when handle lifetimes do not correspond to C++ scopes. Google Chrome, for example, uses persistent handles to refer to Document Object Model (DOM) nodes. A persistent handle can be made weak, using PersistentBase::SetWeak, to trigger a callback from the garbage collector when the only references to an object are from weak persistent handles.
If you need to use data for the execution you must use native c/c++ types and you must do it while creating the class instance, either in the constructor or before calling AsyncQueueWorker (more on this later).

In our example, PiWorker needs the number of points to calculate an estimation of PI, since we don't have access to any of the V8 values that we got in the function arguments (e.g. info[0]), we'll need to convert the value to C type and then use it in the Async Worker Execute.

Now we have created an instance of PiWorker, which inherits from AsyncWorker, we passed the number of points AND the callback which was passed to our CalculateAsync function:


addon.calculateAsync(100, function(err,result){
  if (err){
    console.log("error executing pi calculations", err);
    return;
  }

  console.log("result", result);
});

We can schedule the PiWorker on the threadpool



// Asynchronous access to the `Estimate()` function
NAN_METHOD(CalculateAsync) {
  int points = To<int>(info[0]).FromJust();
  Callback *callback = new Callback(info[1].As<Function>());

  AsyncQueueWorker(new PiWorker(callback, points));
}

actually, when calling AsyncQueueWorker it schedules the Execute for execution and WorkComplete  to execute (on the main thread) when the execution is done.


inline void AsyncExecute (uv_work_t* req) {
  AsyncWorker *worker = static_cast<AsyncWorker*>(req->data);
  worker->Execute();
}

inline void AsyncExecuteComplete (uv_work_t* req) {
  AsyncWorker* worker = static_cast<AsyncWorker*>(req->data);
  worker->WorkComplete();
  worker->Destroy();
}

inline void AsyncQueueWorker (AsyncWorker* worker) {
  uv_queue_work(
      uv_default_loop()
    , &worker->request
    , AsyncExecute
    , reinterpret_cast<uv_after_work_cb>(AsyncExecuteComplete)
  );
}

The Execute method will be executed in one of the threads of the threadpool and when its done, it will execute either the HandleOKCallback or the HandleErrorCallback depending if the SetErrorMessage was called or not.


virtual void WorkComplete() {
  HandleScope scope;

  if (errmsg_ == NULL)
    HandleOKCallback();
  else
    HandleErrorCallback();
  delete callback;
  callback = NULL;
}

So writing Async Callbacks is pretty simple once you understand the program flow.

Source Code:
https://github.com/nodejs/nan/tree/master/examples/async_pi_estimate

Saturday, October 22, 2016

Node js C++ Addon Overload Resolution


Function overloads is not part of javascript as functions are objects inside object properties and object property names are unique.


I've attempted to add overload resolution on top of node js c++ addons for easily importing c++ libraries by having a middleware between v8 and the actual code executed.


Before you read on, make sure you understand Native Abstractions for Node.js (NAN) as it relies on it for some of its functionality and builds on top of it.

You can find the project and its tests at:
https://github.com/drorgl/node-overload-resolution

Structure

overload_resolution - the main class that registers and calls the overloaded functions, it provides a macro POLY_METHOD which is almost identical to NAN_METHOD for declaring functions and calling them after the correct overload has been determined.
by itself, the class does nothing, you will still have to register all the callbacks to overload_resolution::execute function for it to do anything:
Declare a callback:
namespace general_callback {
    std::shared_ptr<overload_resolution> overload;
    NAN_METHOD(tester_callback) {
        return overload->execute("current_namespace", info);
    }
}
in the init function, populate general_callback::overload with overload resolution instance:
general_callback::overload = overload;
and tell v8 you want to callback into tester_callback:
Nan::SetMethod(target, "overloaded_function", general_callback::tester_callback);
now the hook is ready to call overload_resolution::execute whenever overloaded_function is called, but we need to tell overload_resolution which function to call when an overload is matched:
constructor:
overload->addOverloadConstructor(
            "", 
                    "constructor_class_tester", 
                            { std::make_shared<overload_info>("a","Number",Nan::Undefined()) }, 
                                    New_number);
            ^ namespace or empty
                    ^ class name 
                            ^ array of parameter names, types and default values
                              note that Nan::Undefined is used as no default
                                    ^ callback POLY_METHOD
static:
overload->addStaticOverload(
            "", 
                    "constructor_class_tester", 
                            "static_function", 
                                    { std::make_shared<overload_info>("a","String",Nan::Undefined()) }, 
                                            static_function_static_string);
            ^ namespace or empty
                    ^ class name or function group name or empty
                            ^ function name
                                    ^ array of parameter names, types and default values
                                            ^ callback POLY_METHOD
member:
overload->addOverload(
            "", 
                    "constructor_class_tester", 
                            "member_function", 
                                    { std::make_shared<overload_info>("a","Map",Nan::Undefined()) }, 
                                            static_function_instance_map);
            ^ namespace or empty
                    ^ class name
                            ^ function name
                                    ^ array of parameter names, types and default values
                                            ^ callback POLY_METHOD

Issues

Currently the project is working but inefficient, it does a lot behind the scenes to determine which overload should be called and hopefully the performance issues will be resolved in the future, the slowest actions are around structs, which are very slow, they were intended as automatic object structure recognition and overload resolution accordingly.

Tests

Attempts were made to have as many tests as possible, at the moment of this update there are 2336 tests, all pass.

Future

If there will be future development, it should do the following:
  • performance analysis, solve the struct performance, check prototype inheritance performance and correctness, check big arrays performance.
  • implement macros
  • cleanup function registration
  • add logging and instrumentation

Monday, October 10, 2016

Lens Adventure

Recently I wanted to add an ultra wide angle lens to my photography skills, I've looked around and in my budget I've found only manual 2nd hand lenses, but then I've seen someone selling Canon 16-35 2.8 II in my budget, the problem was, it needed repair, the auto-focus and aperture didn't work and the lens would show ERR 1, but I thought about using it as a manual lens and I've decided to get into that adventure and see if I can fix it myself, not before looking all over eBay and aliexpress for replacement parts should I need it.

I've looked at some YouTube videos showing disassembly of that lens.

This one from TechnologyMafia shows a disassembly of this lens, I've learned a lot from it, though it didn't show some parts, like how to get the front element disassembled but it does show how the lens is constructed.



There's also this video by Jakob Dral, which shows a general workflow of how to order the disassembled parts so you can put it back together without "extra" screws, this guy has skills!



There's a full disassembly of the 24-105 by Francesco Capasso, which is pretty similar internally, this series of videos (1-5) is very good in terms of understanding how things fit together.



And I've found plenty of pictures for a different (yet somewhat similar) Canon 16-35 F4 by Roger Cicala from LensRentals.com, Thanks Roger for permission to use your pictures!

But in the end, no amount of videos are going to show how to fix your own lens, its only learning tools to make the experience more intuitive.

So after buying the lens and actually trying it for a minute or two, I had a feeling there's a problem in the bayonet, the errors and behavior of lens made me think its an electrical problem, so after opening the bayonet, I've checked the electrical connections and I've found out this ribbon is broken:


I didn't have too much patience to wait for a month, so I've attempted to repair it. In the "old days" we used to scrape some coating off the conductors and and solder them, but I remembered the coating would melt in the heat and I had an old broken 18-55 that I got as a "gift" so I've decided to try on it first. I've disassembled it and attempted to solder the ribbon, apparently things changed and 350C didn't melt the ribbon.

So, I've attempted to do that on the real thing and closed the lens and..... great! no more error 1!!


This is where the ribbon break. The one thing I didn't take a picture of... Thanks Roger for the image!

But the story doesn't end there. after playing with it for a few minutes I've discovered that it works great in aperture 2.8 but as soon as you change the aperture error 1 comes back.

I've looked up the prices for a new aperture diaphragm

(from here)

and a new ribbon cable for the diaphragm 

(from here)

and decided to try a disassembly practice to see if I can do it myself or give up and take it to a professional.



It took me a few hours, I wanted to do it right, disassemble it without using any force and take breaks every time my hands would start shaking or I lost the needed patience. 

Eventually I got to the focus element group and decided to stop since it looked like too many steps for my comfort zone which I pushed too far anyway.

I've decided to stop playing with it, clean all the elements thoroughly with lens cleaning pads and close it until the parts came in the mail, so I closed it up, connected all the ribbons and surprisingly it worked. so in the end it wasn't the diaphragm or the flexible cables, it was just a bad connection to the controller board. :-)


My take from this experience:
- Lens are exact science (obviously), so anything you take apart, no matter how simple it looks (like screws) probably have orientation and have been calibrated, these small plastic spacers most likely have orientation, mark it with a permanent marker on different angles (so you won't confuse between them) and its likely you'll be able to put it back together without ruining the calibration.
Mark the orientation! if you look closely, it has a thick side and thin side, so its actually a micro adjustment of the front element.

- Flexible ribbons are delicate, not feather delicate but enough to tear accidentally, before removing or replacing a part, look all around it that no ribbon has been caught between unintended parts.

- STOP as soon as you're starting to loose patience, next step will be a mistake.
- STOP as soon as your hands are starting to shake, next step will be a screw flying somewhere you didn't want.

I took breaks between sections, it helped me remember what goes where, I took plenty of photos of "before" so if I do forget, I'll have some kind of record of how things looked before.

At the moment the lens works, the focus is accurate but I didn't check it with a test pattern, there's a chance its not, in F5.6 its pretty sharp but in F2.8 the DOF is too shallow to be sure without a thorough test.

Experience rating, 9, it was fun, scary, interesting and I've learned a lot about canon 16-35, it has a solid build! let the photography experience begin! :-)

UPDATE Nov 3rd:
I've ordered a front barrel since the one this lens had was somewhat heavily used and dented, so here's how it looks now





Saturday, September 24, 2016

Learning about V8 Objects

V8 Objects are documented thoroughly, however, reading documentation doesn't always help when you want to know how exactly it will manifest when calling a function with particular set of parameters in a particular state.

I've wrote this helper project to determine the exact values for each function call.

for example:

- calling a function without any parameters yields the following Nan::NAN_METHOD_ARGS_TYPE info

1:  {  
2:      "Length": 0,  
3:      "Callee": {  
4:          "IsUndefined": false,  
5:          "IsNull": false,  
6:          "IsTrue": false,  
7:          "IsFalse": false,  
8:          "IsName": false,  
9:          "IsString": false,  
10:          "IsSymbol": false,  
11:          "IsFunction": true,  
12:          "GetName": "test",  
13:          "GetInferredName": "",  
14:          "GetDebugName": "test",  
15:          "GetScriptLineNumber": -1,  
16:          "GetScriptColumnNumber": -1,  
17:          "IsBuiltin": true,  
18:          "ScriptId": 0,  
19:          "GetScriptOrigin": {  
20:              "Options": {  
21:                  "IsEmbedderDebugScript": false,  
22:                  "IsSharedCrossOrigin": false,  
23:                  "IsOpaque": false,  
24:                  "Flags": 0  
25:              }  
26:          },  
27:          "IsArray": false,  
28:          "IsObject": true,  
29:          "PropertyNames": [],  
30:          "GetConstructorName": "Function",  
31:          "InternalFieldCount": 0,  
32:          "HasNamedLookupInterceptor": false,  
33:          "HasIndexedLookupInterceptor": false,  
34:          "GetIdentityHash": 535707258,  
35:          "IsCallable": true,  
36:          "GetPrototype": {  
37:              "IsUndefined": false,  
38:              "IsNull": false,  
39:              "IsTrue": false,  
40:              "IsFalse": false,  
41:              "IsName": false,  
42:              "IsString": false,  
43:              "IsSymbol": false,  
44:              "IsFunction": true,  
45:              "IsArray": false,  
46:              "IsObject": true,  
47:              "IsBoolean": false,  
48:              "IsNumber": false,  
49:              "IsExternal": false,  
50:              "IsInt32": false,  
51:              "IsUint32": false,  
52:              "IsDate": false,  
53:              "IsArgumentsObject": false,  
54:              "IsBooleanObject": false,  
55:              "IsNumberObject": false,  
56:              "IsStringObject": false,  
57:              "IsSymbolObject": false,  
58:              "IsNativeError": false,  
59:              "IsRegExp": false,  
60:              "IsGeneratorFunction": false,  
61:              "IsGeneratorObject": false,  
62:              "IsPromise": false,  
63:              "IsMap": false,  
64:              "IsSet": false,  
65:              "IsMapIterator": false,  
66:              "IsSetIterator": false,  
67:              "IsWeakMap": false,  
68:              "IsWeakSet": false,  
69:              "IsArrayBuffer": false,  
70:              "IsArrayBufferView": false,  
71:              "IsTypedArray": false,  
72:              "IsUint8Array": false,  
73:              "IsUint8ClampedArray": false,  
74:              "IsInt8Array": false,  
75:              "IsUint16Array": false,  
76:              "IsInt16Array": false,  
77:              "IsUint32Array": false,  
78:              "IsInt32Array": false,  
79:              "IsFloat32Array": false,  
80:              "IsFloat64Array": false,  
81:              "IsDataView": false,  
82:              "IsSharedArrayBuffer": false,  
83:              "IsProxy": false,  
84:              "ToBoolean": true,  
85:              "ToNumber": null,  
86:              "ToString": "function () {}",  
87:              "ToDetailString": "function () {}",  
88:              "ToInteger": 0,  
89:              "ToUint32": 0,  
90:              "ToInt32": 0,  
91:              "BooleanValue": true,  
92:              "NumberValue": null,  
93:              "IntegerValue": 0,  
94:              "Uint32Value": 0,  
95:              "Int32Value": 0,  
96:              "PropertyNames": [],  
97:              "GetConstructorName": "Function",  
98:              "InternalFieldCount": 0,  
99:              "HasNamedLookupInterceptor": false,  
100:              "HasIndexedLookupInterceptor": false,  
101:              "GetIdentityHash": 2033009011,  
102:              "IsCallable": true  
103:          },  
104:          "IsBoolean": false,  
105:          "IsNumber": false,  
106:          "IsExternal": false,  
107:          "IsInt32": false,  
108:          "IsUint32": false,  
109:          "IsDate": false,  
110:          "IsArgumentsObject": false,  
111:          "IsBooleanObject": false,  
112:          "IsNumberObject": false,  
113:          "IsStringObject": false,  
114:          "IsSymbolObject": false,  
115:          "IsNativeError": false,  
116:          "IsRegExp": false,  
117:          "IsGeneratorFunction": false,  
118:          "IsGeneratorObject": false,  
119:          "IsPromise": false,  
120:          "IsMap": false,  
121:          "IsSet": false,  
122:          "IsMapIterator": false,  
123:          "IsSetIterator": false,  
124:          "IsWeakMap": false,  
125:          "IsWeakSet": false,  
126:          "IsArrayBuffer": false,  
127:          "IsArrayBufferView": false,  
128:          "IsTypedArray": false,  
129:          "IsUint8Array": false,  
130:          "IsUint8ClampedArray": false,  
131:          "IsInt8Array": false,  
132:          "IsUint16Array": false,  
133:          "IsInt16Array": false,  
134:          "IsUint32Array": false,  
135:          "IsInt32Array": false,  
136:          "IsFloat32Array": false,  
137:          "IsFloat64Array": false,  
138:          "IsDataView": false,  
139:          "IsSharedArrayBuffer": false,  
140:          "IsProxy": false,  
141:          "ToBoolean": true,  
142:          "ToNumber": null,  
143:          "ToString": "function test() { [native code] }",  
144:          "ToDetailString": "function test() { [native code] }",  
145:          "ToInteger": 0,  
146:          "ToUint32": 0,  
147:          "ToInt32": 0,  
148:          "BooleanValue": true,  
149:          "NumberValue": null,  
150:          "IntegerValue": 0,  
151:          "Uint32Value": 0,  
152:          "Int32Value": 0  
153:      },  
154:      "IsConstructCall": false,  
155:      "This": {  
156:          "IsUndefined": false,  
157:          "IsNull": false,  
158:          "IsTrue": false,  
159:          "IsFalse": false,  
160:          "IsName": false,  
161:          "IsString": false,  
162:          "IsSymbol": false,  
163:          "IsFunction": false,  
164:          "IsArray": false,  
165:          "IsObject": true,  
166:          "PropertyNames": [],  
167:          "GetConstructorName": "Object",  
168:          "InternalFieldCount": 0,  
169:          "HasNamedLookupInterceptor": false,  
170:          "HasIndexedLookupInterceptor": false,  
171:          "GetIdentityHash": 716126579,  
172:          "IsCallable": false,  
173:          "GetPrototype": {  
174:              "IsUndefined": false,  
175:              "IsNull": false,  
176:              "IsTrue": false,  
177:              "IsFalse": false,  
178:              "IsName": false,  
179:              "IsString": false,  
180:              "IsSymbol": false,  
181:              "IsFunction": false,  
182:              "IsArray": false,  
183:              "IsObject": true,  
184:              "IsBoolean": false,  
185:              "IsNumber": false,  
186:              "IsExternal": false,  
187:              "IsInt32": false,  
188:              "IsUint32": false,  
189:              "IsDate": false,  
190:              "IsArgumentsObject": false,  
191:              "IsBooleanObject": false,  
192:              "IsNumberObject": false,  
193:              "IsStringObject": false,  
194:              "IsSymbolObject": false,  
195:              "IsNativeError": false,  
196:              "IsRegExp": false,  
197:              "IsGeneratorFunction": false,  
198:              "IsGeneratorObject": false,  
199:              "IsPromise": false,  
200:              "IsMap": false,  
201:              "IsSet": false,  
202:              "IsMapIterator": false,  
203:              "IsSetIterator": false,  
204:              "IsWeakMap": false,  
205:              "IsWeakSet": false,  
206:              "IsArrayBuffer": false,  
207:              "IsArrayBufferView": false,  
208:              "IsTypedArray": false,  
209:              "IsUint8Array": false,  
210:              "IsUint8ClampedArray": false,  
211:              "IsInt8Array": false,  
212:              "IsUint16Array": false,  
213:              "IsInt16Array": false,  
214:              "IsUint32Array": false,  
215:              "IsInt32Array": false,  
216:              "IsFloat32Array": false,  
217:              "IsFloat64Array": false,  
218:              "IsDataView": false,  
219:              "IsSharedArrayBuffer": false,  
220:              "IsProxy": false,  
221:              "ToBoolean": true,  
222:              "ToNumber": null,  
223:              "ToString": "[object Object]",  
224:              "ToDetailString": "#<Object>",  
225:              "ToObject": {},  
226:              "ToInteger": 0,  
227:              "ToUint32": 0,  
228:              "ToInt32": 0,  
229:              "BooleanValue": true,  
230:              "NumberValue": null,  
231:              "IntegerValue": 0,  
232:              "Uint32Value": 0,  
233:              "Int32Value": 0,  
234:              "PropertyNames": [],  
235:              "GetConstructorName": "Object",  
236:              "InternalFieldCount": 0,  
237:              "HasNamedLookupInterceptor": false,  
238:              "HasIndexedLookupInterceptor": false,  
239:              "GetIdentityHash": 1536014436,  
240:              "IsCallable": false  
241:          },  
242:          "IsBoolean": false,  
243:          "IsNumber": false,  
244:          "IsExternal": false,  
245:          "IsInt32": false,  
246:          "IsUint32": false,  
247:          "IsDate": false,  
248:          "IsArgumentsObject": false,  
249:          "IsBooleanObject": false,  
250:          "IsNumberObject": false,  
251:          "IsStringObject": false,  
252:          "IsSymbolObject": false,  
253:          "IsNativeError": false,  
254:          "IsRegExp": false,  
255:          "IsGeneratorFunction": false,  
256:          "IsGeneratorObject": false,  
257:          "IsPromise": false,  
258:          "IsMap": false,  
259:          "IsSet": false,  
260:          "IsMapIterator": false,  
261:          "IsSetIterator": false,  
262:          "IsWeakMap": false,  
263:          "IsWeakSet": false,  
264:          "IsArrayBuffer": false,  
265:          "IsArrayBufferView": false,  
266:          "IsTypedArray": false,  
267:          "IsUint8Array": false,  
268:          "IsUint8ClampedArray": false,  
269:          "IsInt8Array": false,  
270:          "IsUint16Array": false,  
271:          "IsInt16Array": false,  
272:          "IsUint32Array": false,  
273:          "IsInt32Array": false,  
274:          "IsFloat32Array": false,  
275:          "IsFloat64Array": false,  
276:          "IsDataView": false,  
277:          "IsSharedArrayBuffer": false,  
278:          "IsProxy": false,  
279:          "ToBoolean": true,  
280:          "ToNumber": null,  
281:          "ToString": "[object Object]",  
282:          "ToDetailString": "#<Object>",  
283:          "ToObject": {},  
284:          "ToInteger": 0,  
285:          "ToUint32": 0,  
286:          "ToInt32": 0,  
287:          "BooleanValue": true,  
288:          "NumberValue": null,  
289:          "IntegerValue": 0,  
290:          "Uint32Value": 0,  
291:          "Int32Value": 0  
292:      },  
293:      "Info": []  
294:  }  


- calling a member function (prototype) yields:

1:   {  
2:      "Length": 0,  
3:      "Callee": {  
4:          "IsUndefined": false,  
5:          "IsNull": false,  
6:          "IsTrue": false,  
7:          "IsFalse": false,  
8:          "IsName": false,  
9:          "IsString": false,  
10:          "IsSymbol": false,  
11:          "IsFunction": true,  
12:          "GetName": "test_member_function",  
13:          "GetInferredName": "",  
14:          "GetDebugName": "test_member_function",  
15:          "GetScriptLineNumber": -1,  
16:          "GetScriptColumnNumber": -1,  
17:          "IsBuiltin": true,  
18:          "ScriptId": 0,  
19:          "GetScriptOrigin": {  
20:              "Options": {  
21:                  "IsEmbedderDebugScript": false,  
22:                  "IsSharedCrossOrigin": false,  
23:                  "IsOpaque": false,  
24:                  "Flags": 0  
25:              }  
26:          },  
27:          "IsArray": false,  
28:          "IsObject": true,  
29:          "PropertyNames": [],  
30:          "GetConstructorName": "Function",  
31:          "InternalFieldCount": 0,  
32:          "HasNamedLookupInterceptor": false,  
33:          "HasIndexedLookupInterceptor": false,  
34:          "GetIdentityHash": 1864397598,  
35:          "IsCallable": true,  
36:          "GetPrototype": {  
37:              "IsUndefined": false,  
38:              "IsNull": false,  
39:              "IsTrue": false,  
40:              "IsFalse": false,  
41:              "IsName": false,  
42:              "IsString": false,  
43:              "IsSymbol": false,  
44:              "IsFunction": true,  
45:              "IsArray": false,  
46:              "IsObject": true,  
47:              "IsBoolean": false,  
48:              "IsNumber": false,  
49:              "IsExternal": false,  
50:              "IsInt32": false,  
51:              "IsUint32": false,  
52:              "IsDate": false,  
53:              "IsArgumentsObject": false,  
54:              "IsBooleanObject": false,  
55:              "IsNumberObject": false,  
56:              "IsStringObject": false,  
57:              "IsSymbolObject": false,  
58:              "IsNativeError": false,  
59:              "IsRegExp": false,  
60:              "IsGeneratorFunction": false,  
61:              "IsGeneratorObject": false,  
62:              "IsPromise": false,  
63:              "IsMap": false,  
64:              "IsSet": false,  
65:              "IsMapIterator": false,  
66:              "IsSetIterator": false,  
67:              "IsWeakMap": false,  
68:              "IsWeakSet": false,  
69:              "IsArrayBuffer": false,  
70:              "IsArrayBufferView": false,  
71:              "IsTypedArray": false,  
72:              "IsUint8Array": false,  
73:              "IsUint8ClampedArray": false,  
74:              "IsInt8Array": false,  
75:              "IsUint16Array": false,  
76:              "IsInt16Array": false,  
77:              "IsUint32Array": false,  
78:              "IsInt32Array": false,  
79:              "IsFloat32Array": false,  
80:              "IsFloat64Array": false,  
81:              "IsDataView": false,  
82:              "IsSharedArrayBuffer": false,  
83:              "IsProxy": false,  
84:              "ToBoolean": true,  
85:              "ToNumber": null,  
86:              "ToString": "function () {}",  
87:              "ToDetailString": "function () {}",  
88:              "ToInteger": 0,  
89:              "ToUint32": 0,  
90:              "ToInt32": 0,  
91:              "BooleanValue": true,  
92:              "NumberValue": null,  
93:              "IntegerValue": 0,  
94:              "Uint32Value": 0,  
95:              "Int32Value": 0,  
96:              "PropertyNames": [],  
97:              "GetConstructorName": "Function",  
98:              "InternalFieldCount": 0,  
99:              "HasNamedLookupInterceptor": false,  
100:              "HasIndexedLookupInterceptor": false,  
101:              "GetIdentityHash": 1117981863,  
102:              "IsCallable": true  
103:          },  
104:          "IsBoolean": false,  
105:          "IsNumber": false,  
106:          "IsExternal": false,  
107:          "IsInt32": false,  
108:          "IsUint32": false,  
109:          "IsDate": false,  
110:          "IsArgumentsObject": false,  
111:          "IsBooleanObject": false,  
112:          "IsNumberObject": false,  
113:          "IsStringObject": false,  
114:          "IsSymbolObject": false,  
115:          "IsNativeError": false,  
116:          "IsRegExp": false,  
117:          "IsGeneratorFunction": false,  
118:          "IsGeneratorObject": false,  
119:          "IsPromise": false,  
120:          "IsMap": false,  
121:          "IsSet": false,  
122:          "IsMapIterator": false,  
123:          "IsSetIterator": false,  
124:          "IsWeakMap": false,  
125:          "IsWeakSet": false,  
126:          "IsArrayBuffer": false,  
127:          "IsArrayBufferView": false,  
128:          "IsTypedArray": false,  
129:          "IsUint8Array": false,  
130:          "IsUint8ClampedArray": false,  
131:          "IsInt8Array": false,  
132:          "IsUint16Array": false,  
133:          "IsInt16Array": false,  
134:          "IsUint32Array": false,  
135:          "IsInt32Array": false,  
136:          "IsFloat32Array": false,  
137:          "IsFloat64Array": false,  
138:          "IsDataView": false,  
139:          "IsSharedArrayBuffer": false,  
140:          "IsProxy": false,  
141:          "ToBoolean": true,  
142:          "ToNumber": null,  
143:          "ToString": "function test_member_function() { [native code] }",  
144:          "ToDetailString": "function test_member_function() { [native code] }",  
145:          "ToInteger": 0,  
146:          "ToUint32": 0,  
147:          "ToInt32": 0,  
148:          "BooleanValue": true,  
149:          "NumberValue": null,  
150:          "IntegerValue": 0,  
151:          "Uint32Value": 0,  
152:          "Int32Value": 0  
153:      },  
154:      "IsConstructCall": false,  
155:      "This": {  
156:          "IsUndefined": false,  
157:          "IsNull": false,  
158:          "IsTrue": false,  
159:          "IsFalse": false,  
160:          "IsName": false,  
161:          "IsString": false,  
162:          "IsSymbol": false,  
163:          "IsFunction": false,  
164:          "IsArray": false,  
165:          "IsObject": true,  
166:          "PropertyNames": [],  
167:          "GetConstructorName": "base_class",  
168:          "InternalFieldCount": 1,  
169:          "HasNamedLookupInterceptor": false,  
170:          "HasIndexedLookupInterceptor": false,  
171:          "GetIdentityHash": 1554520219,  
172:          "IsCallable": false,  
173:          "GetPrototype": {  
174:              "IsUndefined": false,  
175:              "IsNull": false,  
176:              "IsTrue": false,  
177:              "IsFalse": false,  
178:              "IsName": false,  
179:              "IsString": false,  
180:              "IsSymbol": false,  
181:              "IsFunction": false,  
182:              "IsArray": false,  
183:              "IsObject": true,  
184:              "IsBoolean": false,  
185:              "IsNumber": false,  
186:              "IsExternal": false,  
187:              "IsInt32": false,  
188:              "IsUint32": false,  
189:              "IsDate": false,  
190:              "IsArgumentsObject": false,  
191:              "IsBooleanObject": false,  
192:              "IsNumberObject": false,  
193:              "IsStringObject": false,  
194:              "IsSymbolObject": false,  
195:              "IsNativeError": false,  
196:              "IsRegExp": false,  
197:              "IsGeneratorFunction": false,  
198:              "IsGeneratorObject": false,  
199:              "IsPromise": false,  
200:              "IsMap": false,  
201:              "IsSet": false,  
202:              "IsMapIterator": false,  
203:              "IsSetIterator": false,  
204:              "IsWeakMap": false,  
205:              "IsWeakSet": false,  
206:              "IsArrayBuffer": false,  
207:              "IsArrayBufferView": false,  
208:              "IsTypedArray": false,  
209:              "IsUint8Array": false,  
210:              "IsUint8ClampedArray": false,  
211:              "IsInt8Array": false,  
212:              "IsUint16Array": false,  
213:              "IsInt16Array": false,  
214:              "IsUint32Array": false,  
215:              "IsInt32Array": false,  
216:              "IsFloat32Array": false,  
217:              "IsFloat64Array": false,  
218:              "IsDataView": false,  
219:              "IsSharedArrayBuffer": false,  
220:              "IsProxy": false,  
221:              "ToBoolean": true,  
222:              "ToNumber": null,  
223:              "ToString": "[object Object]",  
224:              "ToDetailString": "#<base_class>",  
225:              "ToObject": {},  
226:              "ToInteger": 0,  
227:              "ToUint32": 0,  
228:              "ToInt32": 0,  
229:              "BooleanValue": true,  
230:              "NumberValue": null,  
231:              "IntegerValue": 0,  
232:              "Uint32Value": 0,  
233:              "Int32Value": 0,  
234:              "PropertyNames": [],  
235:              "GetConstructorName": "Object",  
236:              "InternalFieldCount": 0,  
237:              "HasNamedLookupInterceptor": false,  
238:              "HasIndexedLookupInterceptor": false,  
239:              "GetIdentityHash": 1008670604,  
240:              "IsCallable": false  
241:          },  
242:          "IsBoolean": false,  
243:          "IsNumber": false,  
244:          "IsExternal": false,  
245:          "IsInt32": false,  
246:          "IsUint32": false,  
247:          "IsDate": false,  
248:          "IsArgumentsObject": false,  
249:          "IsBooleanObject": false,  
250:          "IsNumberObject": false,  
251:          "IsStringObject": false,  
252:          "IsSymbolObject": false,  
253:          "IsNativeError": false,  
254:          "IsRegExp": false,  
255:          "IsGeneratorFunction": false,  
256:          "IsGeneratorObject": false,  
257:          "IsPromise": false,  
258:          "IsMap": false,  
259:          "IsSet": false,  
260:          "IsMapIterator": false,  
261:          "IsSetIterator": false,  
262:          "IsWeakMap": false,  
263:          "IsWeakSet": false,  
264:          "IsArrayBuffer": false,  
265:          "IsArrayBufferView": false,  
266:          "IsTypedArray": false,  
267:          "IsUint8Array": false,  
268:          "IsUint8ClampedArray": false,  
269:          "IsInt8Array": false,  
270:          "IsUint16Array": false,  
271:          "IsInt16Array": false,  
272:          "IsUint32Array": false,  
273:          "IsInt32Array": false,  
274:          "IsFloat32Array": false,  
275:          "IsFloat64Array": false,  
276:          "IsDataView": false,  
277:          "IsSharedArrayBuffer": false,  
278:          "IsProxy": false,  
279:          "ToBoolean": true,  
280:          "ToNumber": null,  
281:          "ToString": "[object base_class]",  
282:          "ToDetailString": "#<base_class>",  
283:          "ToObject": {},  
284:          "ToInteger": 0,  
285:          "ToUint32": 0,  
286:          "ToInt32": 0,  
287:          "BooleanValue": true,  
288:          "NumberValue": null,  
289:          "IntegerValue": 0,  
290:          "Uint32Value": 0,  
291:          "Int32Value": 0  
292:      },  
293:      "Info": []  
294:  }  


- calling a "static" function yields:

1:  {  
2:      "Length": 0,  
3:      "Callee": {  
4:          "IsUndefined": false,  
5:          "IsNull": false,  
6:          "IsTrue": false,  
7:          "IsFalse": false,  
8:          "IsName": false,  
9:          "IsString": false,  
10:          "IsSymbol": false,  
11:          "IsFunction": true,  
12:          "GetName": "test_static_function",  
13:          "GetInferredName": "",  
14:          "GetDebugName": "test_static_function",  
15:          "GetScriptLineNumber": -1,  
16:          "GetScriptColumnNumber": -1,  
17:          "IsBuiltin": true,  
18:          "ScriptId": 0,  
19:          "GetScriptOrigin": {  
20:              "Options": {  
21:                  "IsEmbedderDebugScript": false,  
22:                  "IsSharedCrossOrigin": false,  
23:                  "IsOpaque": false,  
24:                  "Flags": 0  
25:              }  
26:          },  
27:          "IsArray": false,  
28:          "IsObject": true,  
29:          "PropertyNames": [],  
30:          "GetConstructorName": "Function",  
31:          "InternalFieldCount": 0,  
32:          "HasNamedLookupInterceptor": false,  
33:          "HasIndexedLookupInterceptor": false,  
34:          "GetIdentityHash": 994160730,  
35:          "IsCallable": true,  
36:          "GetPrototype": {  
37:              "IsUndefined": false,  
38:              "IsNull": false,  
39:              "IsTrue": false,  
40:              "IsFalse": false,  
41:              "IsName": false,  
42:              "IsString": false,  
43:              "IsSymbol": false,  
44:              "IsFunction": true,  
45:              "IsArray": false,  
46:              "IsObject": true,  
47:              "IsBoolean": false,  
48:              "IsNumber": false,  
49:              "IsExternal": false,  
50:              "IsInt32": false,  
51:              "IsUint32": false,  
52:              "IsDate": false,  
53:              "IsArgumentsObject": false,  
54:              "IsBooleanObject": false,  
55:              "IsNumberObject": false,  
56:              "IsStringObject": false,  
57:              "IsSymbolObject": false,  
58:              "IsNativeError": false,  
59:              "IsRegExp": false,  
60:              "IsGeneratorFunction": false,  
61:              "IsGeneratorObject": false,  
62:              "IsPromise": false,  
63:              "IsMap": false,  
64:              "IsSet": false,  
65:              "IsMapIterator": false,  
66:              "IsSetIterator": false,  
67:              "IsWeakMap": false,  
68:              "IsWeakSet": false,  
69:              "IsArrayBuffer": false,  
70:              "IsArrayBufferView": false,  
71:              "IsTypedArray": false,  
72:              "IsUint8Array": false,  
73:              "IsUint8ClampedArray": false,  
74:              "IsInt8Array": false,  
75:              "IsUint16Array": false,  
76:              "IsInt16Array": false,  
77:              "IsUint32Array": false,  
78:              "IsInt32Array": false,  
79:              "IsFloat32Array": false,  
80:              "IsFloat64Array": false,  
81:              "IsDataView": false,  
82:              "IsSharedArrayBuffer": false,  
83:              "IsProxy": false,  
84:              "ToBoolean": true,  
85:              "ToNumber": null,  
86:              "ToString": "function () {}",  
87:              "ToDetailString": "function () {}",  
88:              "ToInteger": 0,  
89:              "ToUint32": 0,  
90:              "ToInt32": 0,  
91:              "BooleanValue": true,  
92:              "NumberValue": null,  
93:              "IntegerValue": 0,  
94:              "Uint32Value": 0,  
95:              "Int32Value": 0,  
96:              "PropertyNames": [],  
97:              "GetConstructorName": "Function",  
98:              "InternalFieldCount": 0,  
99:              "HasNamedLookupInterceptor": false,  
100:              "HasIndexedLookupInterceptor": false,  
101:              "GetIdentityHash": 1329899702,  
102:              "IsCallable": true  
103:          },  
104:          "IsBoolean": false,  
105:          "IsNumber": false,  
106:          "IsExternal": false,  
107:          "IsInt32": false,  
108:          "IsUint32": false,  
109:          "IsDate": false,  
110:          "IsArgumentsObject": false,  
111:          "IsBooleanObject": false,  
112:          "IsNumberObject": false,  
113:          "IsStringObject": false,  
114:          "IsSymbolObject": false,  
115:          "IsNativeError": false,  
116:          "IsRegExp": false,  
117:          "IsGeneratorFunction": false,  
118:          "IsGeneratorObject": false,  
119:          "IsPromise": false,  
120:          "IsMap": false,  
121:          "IsSet": false,  
122:          "IsMapIterator": false,  
123:          "IsSetIterator": false,  
124:          "IsWeakMap": false,  
125:          "IsWeakSet": false,  
126:          "IsArrayBuffer": false,  
127:          "IsArrayBufferView": false,  
128:          "IsTypedArray": false,  
129:          "IsUint8Array": false,  
130:          "IsUint8ClampedArray": false,  
131:          "IsInt8Array": false,  
132:          "IsUint16Array": false,  
133:          "IsInt16Array": false,  
134:          "IsUint32Array": false,  
135:          "IsInt32Array": false,  
136:          "IsFloat32Array": false,  
137:          "IsFloat64Array": false,  
138:          "IsDataView": false,  
139:          "IsSharedArrayBuffer": false,  
140:          "IsProxy": false,  
141:          "ToBoolean": true,  
142:          "ToNumber": null,  
143:          "ToString": "function test_static_function() { [native code] }",  
144:          "ToDetailString": "function test_static_function() { [native code] }",  
145:          "ToInteger": 0,  
146:          "ToUint32": 0,  
147:          "ToInt32": 0,  
148:          "BooleanValue": true,  
149:          "NumberValue": null,  
150:          "IntegerValue": 0,  
151:          "Uint32Value": 0,  
152:          "Int32Value": 0  
153:      },  
154:      "IsConstructCall": false,  
155:      "This": {  
156:          "IsUndefined": false,  
157:          "IsNull": false,  
158:          "IsTrue": false,  
159:          "IsFalse": false,  
160:          "IsName": false,  
161:          "IsString": false,  
162:          "IsSymbol": false,  
163:          "IsFunction": true,  
164:          "GetName": "base_class",  
165:          "GetInferredName": "",  
166:          "GetDebugName": "base_class",  
167:          "GetScriptLineNumber": -1,  
168:          "GetScriptColumnNumber": -1,  
169:          "IsBuiltin": true,  
170:          "ScriptId": 0,  
171:          "GetScriptOrigin": {  
172:              "Options": {  
173:                  "IsEmbedderDebugScript": false,  
174:                  "IsSharedCrossOrigin": false,  
175:                  "IsOpaque": false,  
176:                  "Flags": 0  
177:              }  
178:          },  
179:          "IsArray": false,  
180:          "IsObject": true,  
181:          "PropertyNames": [],  
182:          "GetConstructorName": "Function",  
183:          "InternalFieldCount": 0,  
184:          "HasNamedLookupInterceptor": false,  
185:          "HasIndexedLookupInterceptor": false,  
186:          "GetIdentityHash": 612374797,  
187:          "IsCallable": true,  
188:          "GetPrototype": {  
189:              "IsUndefined": false,  
190:              "IsNull": false,  
191:              "IsTrue": false,  
192:              "IsFalse": false,  
193:              "IsName": false,  
194:              "IsString": false,  
195:              "IsSymbol": false,  
196:              "IsFunction": true,  
197:              "IsArray": false,  
198:              "IsObject": true,  
199:              "IsBoolean": false,  
200:              "IsNumber": false,  
201:              "IsExternal": false,  
202:              "IsInt32": false,  
203:              "IsUint32": false,  
204:              "IsDate": false,  
205:              "IsArgumentsObject": false,  
206:              "IsBooleanObject": false,  
207:              "IsNumberObject": false,  
208:              "IsStringObject": false,  
209:              "IsSymbolObject": false,  
210:              "IsNativeError": false,  
211:              "IsRegExp": false,  
212:              "IsGeneratorFunction": false,  
213:              "IsGeneratorObject": false,  
214:              "IsPromise": false,  
215:              "IsMap": false,  
216:              "IsSet": false,  
217:              "IsMapIterator": false,  
218:              "IsSetIterator": false,  
219:              "IsWeakMap": false,  
220:              "IsWeakSet": false,  
221:              "IsArrayBuffer": false,  
222:              "IsArrayBufferView": false,  
223:              "IsTypedArray": false,  
224:              "IsUint8Array": false,  
225:              "IsUint8ClampedArray": false,  
226:              "IsInt8Array": false,  
227:              "IsUint16Array": false,  
228:              "IsInt16Array": false,  
229:              "IsUint32Array": false,  
230:              "IsInt32Array": false,  
231:              "IsFloat32Array": false,  
232:              "IsFloat64Array": false,  
233:              "IsDataView": false,  
234:              "IsSharedArrayBuffer": false,  
235:              "IsProxy": false,  
236:              "ToBoolean": true,  
237:              "ToNumber": null,  
238:              "ToString": "function () {}",  
239:              "ToDetailString": "function () {}",  
240:              "ToInteger": 0,  
241:              "ToUint32": 0,  
242:              "ToInt32": 0,  
243:              "BooleanValue": true,  
244:              "NumberValue": null,  
245:              "IntegerValue": 0,  
246:              "Uint32Value": 0,  
247:              "Int32Value": 0,  
248:              "PropertyNames": [],  
249:              "GetConstructorName": "Function",  
250:              "InternalFieldCount": 0,  
251:              "HasNamedLookupInterceptor": false,  
252:              "HasIndexedLookupInterceptor": false,  
253:              "GetIdentityHash": 1329899702,  
254:              "IsCallable": true  
255:          },  
256:          "IsBoolean": false,  
257:          "IsNumber": false,  
258:          "IsExternal": false,  
259:          "IsInt32": false,  
260:          "IsUint32": false,  
261:          "IsDate": false,  
262:          "IsArgumentsObject": false,  
263:          "IsBooleanObject": false,  
264:          "IsNumberObject": false,  
265:          "IsStringObject": false,  
266:          "IsSymbolObject": false,  
267:          "IsNativeError": false,  
268:          "IsRegExp": false,  
269:          "IsGeneratorFunction": false,  
270:          "IsGeneratorObject": false,  
271:          "IsPromise": false,  
272:          "IsMap": false,  
273:          "IsSet": false,  
274:          "IsMapIterator": false,  
275:          "IsSetIterator": false,  
276:          "IsWeakMap": false,  
277:          "IsWeakSet": false,  
278:          "IsArrayBuffer": false,  
279:          "IsArrayBufferView": false,  
280:          "IsTypedArray": false,  
281:          "IsUint8Array": false,  
282:          "IsUint8ClampedArray": false,  
283:          "IsInt8Array": false,  
284:          "IsUint16Array": false,  
285:          "IsInt16Array": false,  
286:          "IsUint32Array": false,  
287:          "IsInt32Array": false,  
288:          "IsFloat32Array": false,  
289:          "IsFloat64Array": false,  
290:          "IsDataView": false,  
291:          "IsSharedArrayBuffer": false,  
292:          "IsProxy": false,  
293:          "ToBoolean": true,  
294:          "ToNumber": null,  
295:          "ToString": "function base_class() { [native code] }",  
296:          "ToDetailString": "function base_class() { [native code] }",  
297:          "ToInteger": 0,  
298:          "ToUint32": 0,  
299:          "ToInt32": 0,  
300:          "BooleanValue": true,  
301:          "NumberValue": null,  
302:          "IntegerValue": 0,  
303:          "Uint32Value": 0,  
304:          "Int32Value": 0  
305:      },  
306:      "Info": []  
307:  }  

There are many more parameters to explore, how does it show when an object is a child of another object? is there really an "int64" value in v8? spoiler: no. Can you do a ToInt32 on float numbers? What's the value of NumberValue for a particular string?

Have fun exploring :-)