1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "gin/wrappable.h"
6
7#include "base/logging.h"
8#include "gin/object_template_builder.h"
9#include "gin/per_isolate_data.h"
10
11namespace gin {
12
13WrappableBase::WrappableBase() {
14}
15
16WrappableBase::~WrappableBase() {
17  wrapper_.Reset();
18}
19
20ObjectTemplateBuilder WrappableBase::GetObjectTemplateBuilder(
21    v8::Isolate* isolate) {
22  return ObjectTemplateBuilder(isolate);
23}
24
25void WrappableBase::WeakCallback(
26    const v8::WeakCallbackData<v8::Object, WrappableBase>& data) {
27  WrappableBase* wrappable = data.GetParameter();
28  wrappable->wrapper_.Reset();
29  delete wrappable;
30}
31
32v8::Handle<v8::Object> WrappableBase::GetWrapperImpl(v8::Isolate* isolate,
33                                                     WrapperInfo* info) {
34  if (!wrapper_.IsEmpty()) {
35    return v8::Local<v8::Object>::New(isolate, wrapper_);
36  }
37
38  PerIsolateData* data = PerIsolateData::From(isolate);
39  v8::Local<v8::ObjectTemplate> templ = data->GetObjectTemplate(info);
40  if (templ.IsEmpty()) {
41    templ = GetObjectTemplateBuilder(isolate).Build();
42    CHECK(!templ.IsEmpty());
43    data->SetObjectTemplate(info, templ);
44  }
45  CHECK_EQ(kNumberOfInternalFields, templ->InternalFieldCount());
46  v8::Handle<v8::Object> wrapper = templ->NewInstance();
47  // |wrapper| may be empty in some extreme cases, e.g., when
48  // Object.prototype.constructor is overwritten.
49  if (wrapper.IsEmpty()) {
50    // The current wrappable object will be no longer managed by V8. Delete this
51    // now.
52    delete this;
53    return wrapper;
54  }
55  wrapper->SetAlignedPointerInInternalField(kWrapperInfoIndex, info);
56  wrapper->SetAlignedPointerInInternalField(kEncodedValueIndex, this);
57  wrapper_.Reset(isolate, wrapper);
58  wrapper_.SetWeak(this, WeakCallback);
59  return wrapper;
60}
61
62namespace internal {
63
64void* FromV8Impl(v8::Isolate* isolate, v8::Handle<v8::Value> val,
65                 WrapperInfo* wrapper_info) {
66  if (!val->IsObject())
67    return NULL;
68  v8::Handle<v8::Object> obj = v8::Handle<v8::Object>::Cast(val);
69  WrapperInfo* info = WrapperInfo::From(obj);
70
71  // If this fails, the object is not managed by Gin. It is either a normal JS
72  // object that's not wrapping any external C++ object, or it is wrapping some
73  // C++ object, but that object isn't managed by Gin (maybe Blink).
74  if (!info)
75    return NULL;
76
77  // If this fails, the object is managed by Gin, but it's not wrapping an
78  // instance of the C++ class associated with wrapper_info.
79  if (info != wrapper_info)
80    return NULL;
81
82  return obj->GetAlignedPointerFromInternalField(kEncodedValueIndex);
83}
84
85}  // namespace internal
86
87}  // namespace gin
88