wrappable.cc 3.13 KB
Newer Older
1 2 3 4 5 6 7
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "gin/wrappable.h"

#include "base/logging.h"
8
#include "gin/object_template_builder.h"
9 10 11 12
#include "gin/per_isolate_data.h"

namespace gin {

13
WrappableBase::WrappableBase() {
14 15
}

16
WrappableBase::~WrappableBase() {
17 18 19
  wrapper_.Reset();
}

20
ObjectTemplateBuilder WrappableBase::GetObjectTemplateBuilder(
21
    v8::Isolate* isolate) {
22
  return ObjectTemplateBuilder(isolate);
23 24
}

25 26
void WrappableBase::FirstWeakCallback(
    const v8::WeakCallbackInfo<WrappableBase>& data) {
27
  WrappableBase* wrappable = data.GetParameter();
28
  wrappable->dead_ = true;
29
  wrappable->wrapper_.Reset();
30 31 32 33 34 35
  data.SetSecondPassCallback(SecondWeakCallback);
}

void WrappableBase::SecondWeakCallback(
    const v8::WeakCallbackInfo<WrappableBase>& data) {
  WrappableBase* wrappable = data.GetParameter();
36
  delete wrappable;
37 38
}

39 40
v8::MaybeLocal<v8::Object> WrappableBase::GetWrapperImpl(v8::Isolate* isolate,
                                                         WrapperInfo* info) {
41
  if (!wrapper_.IsEmpty()) {
42 43
    return v8::MaybeLocal<v8::Object>(
        v8::Local<v8::Object>::New(isolate, wrapper_));
44 45
  }

46 47 48
  if (dead_)
    return v8::MaybeLocal<v8::Object>();

49 50
  PerIsolateData* data = PerIsolateData::From(isolate);
  v8::Local<v8::ObjectTemplate> templ = data->GetObjectTemplate(info);
51
  if (templ.IsEmpty()) {
52
    templ = GetObjectTemplateBuilder(isolate).Build();
53 54 55
    CHECK(!templ.IsEmpty());
    data->SetObjectTemplate(info, templ);
  }
56
  CHECK_EQ(kNumberOfInternalFields, templ->InternalFieldCount());
bashi's avatar
bashi committed
57
  v8::Local<v8::Object> wrapper;
58 59
  // |wrapper| may be empty in some extreme cases, e.g., when
  // Object.prototype.constructor is overwritten.
bashi's avatar
bashi committed
60
  if (!templ->NewInstance(isolate->GetCurrentContext()).ToLocal(&wrapper)) {
61 62 63
    // The current wrappable object will be no longer managed by V8. Delete this
    // now.
    delete this;
64
    return v8::MaybeLocal<v8::Object>(wrapper);
65
  }
66 67 68 69

  int indices[] = {kWrapperInfoIndex, kEncodedValueIndex};
  void* values[] = {info, this};
  wrapper->SetAlignedPointerInInternalFields(2, indices, values);
70
  wrapper_.Reset(isolate, wrapper);
71
  wrapper_.SetWeak(this, FirstWeakCallback, v8::WeakCallbackType::kParameter);
72
  return v8::MaybeLocal<v8::Object>(wrapper);
73 74
}

75 76
namespace internal {

77
void* FromV8Impl(v8::Isolate* isolate, v8::Local<v8::Value> val,
78 79 80
                 WrapperInfo* wrapper_info) {
  if (!val->IsObject())
    return NULL;
81
  v8::Local<v8::Object> obj = v8::Local<v8::Object>::Cast(val);
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
  WrapperInfo* info = WrapperInfo::From(obj);

  // If this fails, the object is not managed by Gin. It is either a normal JS
  // object that's not wrapping any external C++ object, or it is wrapping some
  // C++ object, but that object isn't managed by Gin (maybe Blink).
  if (!info)
    return NULL;

  // If this fails, the object is managed by Gin, but it's not wrapping an
  // instance of the C++ class associated with wrapper_info.
  if (info != wrapper_info)
    return NULL;

  return obj->GetAlignedPointerFromInternalField(kEncodedValueIndex);
}

}  // namespace internal

100
}  // namespace gin