Skip to content

Performance optimizations (V8) - #134

Merged
jasongin merged 2 commits into
nodejs:api-prototype-8.xfrom
jasongin:perf
Mar 9, 2017
Merged

jasongin merged 2 commits into
nodejs:api-prototype-8.xfrom
jasongin:perf

Conversation

@jasongin

@jasongin jasongin commented Mar 7, 2017

Copy link
Copy Markdown
Member
  • Add a napi_get_cb_info function to get args length, args, this, and data in a single call
  • Move the static exception to a class member to enable inlining of the lastException() method.
  • Refactor the CallbackWrapper group of helper classes to avoid most (non-inlinable) virtual function calls
  • Remove use of v8::TryCatch (via NAPI_PREAMBLE) from several places where it shouldn't be needed.

Together, these optimizations reduce the overhead of every JS-to-C++ call through the NAPI layer by approximately 50%.

 - Add a `napi_get_cb_info` function to get args length, args, this, and data in a single call
 - Move the static exception to a class member to enable inlining of the `lastException()` method.
 - Refactor the `CallbackWrapper` group of helper classes to avoid most (non-inlinable) virtual function calls
 - Remove use of `v8::TryCatch` (via `NAPI_PREAMBLE`) from several places where it shouldn't be needed.

Together, these optimizations reduce the overhead of every JS-to-C++ call through the NAPI layer by approximately 50%.
@jasongin jasongin changed the title napi: Performance optimizations Performance optimizations (V8) Mar 7, 2017
@jasongin

jasongin commented Mar 7, 2017

Copy link
Copy Markdown
Member Author

@kkoopa

kkoopa commented Mar 8, 2017

Copy link
Copy Markdown

Would it not be possible to do the same to napi_delete_reference?

napi_status napi_delete_reference(napi_env e, napi_ref ref) {
  NAPI_PREAMBLE(e);
  CHECK_ARG(ref);

  v8impl::Reference* reference = reinterpret_cast<v8impl::Reference*>(ref);
  delete reference;

  return GET_RETURN_STATUS();
}
napi_status napi_delete_reference(napi_env, napi_ref ref) {
  delete static_cast<v8impl::Reference*>(ref);
  return napi_ok;
}

digitalinfinity

This comment was marked as off-topic.

@jasongin

jasongin commented Mar 9, 2017

Copy link
Copy Markdown
Member Author

@kkoopa Yes good point. That one wasn't related to any areas I was focusing on for performance, but the TryCatch obviously isn't necessary there either. I'll make that change.

@jasongin

jasongin commented Mar 9, 2017

Copy link
Copy Markdown
Member Author

Actually I'm not sure about applying that change to napi_delete_reference(), because the v8impl::Reference destructor calls v8::Persistent::Reset(), which might do non-trivial things in the VM.

@kkoopa

kkoopa commented Mar 9, 2017 •

Copy link
Copy Markdown

Define non-trivial. I would not assume that v8::Persistent::Reset() can throw a js exception. It does not even take an Isolate *. All v8::Persistent::Reset() should do is clear the val_ member and the storage cell.

template <class T>
void PersistentBase<T>::Reset() {
  if (this->IsEmpty()) return;
  V8::DisposeGlobal(reinterpret_cast<internal::Object**>(this->val_));
  val_ = 0;
}

void V8::DisposeGlobal(i::Object** location) {
  i::GlobalHandles::Destroy(location);
}

void GlobalHandles::Destroy(Object** location) {
  if (location != NULL) Node::FromLocation(location)->Release();
}

  void Release() {
    DCHECK(IsInUse());
    set_state(FREE);
    // Zap the values for eager trapping.
    object_ = reinterpret_cast<Object*>(kGlobalHandleZapValue);
    class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId;
    set_independent(false);
    set_active(false);
    weak_callback_ = NULL;
    DecreaseBlockUses();
  }
/*-------------------------------------------------------------------------------*/
void GlobalHandles::Node::DecreaseBlockUses() {
  NodeBlock* node_block = FindBlock();
  GlobalHandles* global_handles = node_block->global_handles();
  parameter_or_next_free_.next_free = global_handles->first_free_;
  global_handles->first_free_ = this;
  node_block->DecreaseUses();
  global_handles->isolate()->counters()->global_handles()->Decrement();
  global_handles->number_of_global_handles_--;
}

  void DecreaseUses() {
    DCHECK(used_nodes_ > 0);
    if (--used_nodes_ == 0) {
      if (next_used_ != NULL) next_used_->prev_used_ = prev_used_;
      if (prev_used_ != NULL) prev_used_->next_used_ = next_used_;
      if (this == global_handles_->first_used_block_) {
        global_handles_->first_used_block_ = next_used_;
      }
    }
  }

As far as I see by skimming through the code, it is fairly trivial.

@jasongin

jasongin commented Mar 9, 2017

Copy link
Copy Markdown
Member Author

OK you convinced me, it should be fine then.

@jasongin
jasongin merged commit 1cce8c7 into nodejs:api-prototype-8.x Mar 9, 2017
@jasongin
jasongin deleted the perf branch March 9, 2017 18:23
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

Successfully merging this pull request may close these issues.

3 participants