1 // Copyright 2015 the V8 project 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 "test/cctest/cctest.h"
6 
7 #include "include/v8.h"
8 #include "include/v8-experimental.h"
9 
10 
11 namespace i = v8::internal;
12 
CppAccessor42(const v8::FunctionCallbackInfo<v8::Value> & info)13 static void CppAccessor42(const v8::FunctionCallbackInfo<v8::Value>& info) {
14   info.GetReturnValue().Set(42);
15 }
16 
17 
CppAccessor41(const v8::FunctionCallbackInfo<v8::Value> & info)18 static void CppAccessor41(const v8::FunctionCallbackInfo<v8::Value>& info) {
19   info.GetReturnValue().Set(41);
20 }
21 
22 
FastAccessor(v8::Isolate * isolate)23 v8::experimental::FastAccessorBuilder* FastAccessor(v8::Isolate* isolate) {
24   auto builder = v8::experimental::FastAccessorBuilder::New(isolate);
25   builder->ReturnValue(builder->IntegerConstant(41));
26   return builder;
27 }
28 
29 
TEST(FastAccessors)30 TEST(FastAccessors) {
31   v8::Isolate* isolate = CcTest::isolate();
32   v8::HandleScope scope(isolate);
33   LocalContext env;
34 
35   // We emulate Embedder-created DOM Node instances. Specifically:
36   // - 'parent': FunctionTemplate ~= DOM Node superclass
37   // - 'child':  FunctionTemplate ~= a specific DOM node type, like a <div />
38   //
39   // We'll install both a C++-based and a JS-based accessor on the parent,
40   // and expect it to be callable on the child.
41 
42   // Setup the parent template ( =~ DOM Node w/ accessors).
43   v8::Local<v8::FunctionTemplate> parent = v8::FunctionTemplate::New(isolate);
44   {
45     auto signature = v8::Signature::New(isolate, parent);
46 
47     // cpp accessor as "firstChild":
48     parent->PrototypeTemplate()->SetAccessorProperty(
49         v8_str("firstChild"),
50         v8::FunctionTemplate::New(isolate, CppAccessor42,
51                                   v8::Local<v8::Value>(), signature));
52 
53     // JS accessor as "firstChildRaw":
54     parent->PrototypeTemplate()->SetAccessorProperty(
55         v8_str("firstChildRaw"),
56         v8::FunctionTemplate::NewWithFastHandler(
57             isolate, CppAccessor41, FastAccessor(isolate),
58             v8::Local<v8::Value>(), signature));
59   }
60 
61   // Setup child object ( =~ a specific DOM Node, e.g. a <div> ).
62   // Also, make a creation function on the global object, so we can access it
63   // in a test.
64   v8::Local<v8::FunctionTemplate> child = v8::FunctionTemplate::New(isolate);
65   child->Inherit(parent);
66   CHECK(env->Global()
67             ->Set(env.local(), v8_str("Node"),
68                   child->GetFunction(env.local()).ToLocalChecked())
69             .IsJust());
70 
71   // Setup done: Let's test it:
72 
73   // The simple case: Run it once.
74   ExpectInt32("var n = new Node(); n.firstChild", 42);
75   ExpectInt32("var n = new Node(); n.firstChildRaw", 41);
76 
77   // Run them in a loop. This will likely trigger the optimizing compiler:
78   ExpectInt32(
79       "var m = new Node(); "
80       "var sum = 0; "
81       "for (var i = 0; i < 10; ++i) { "
82       "  sum += m.firstChild; "
83       "  sum += m.firstChildRaw; "
84       "}; "
85       "sum;",
86       10 * (42 + 41));
87 
88   // Obtain the accessor and call it via apply on the Node:
89   ExpectInt32(
90       "var n = new Node(); "
91       "var g = Object.getOwnPropertyDescriptor("
92       "    n.__proto__.__proto__, 'firstChild')['get']; "
93       "g.apply(n);",
94       42);
95   ExpectInt32(
96       "var n = new Node(); "
97       "var g = Object.getOwnPropertyDescriptor("
98       "    n.__proto__.__proto__, 'firstChildRaw')['get']; "
99       "g.apply(n);",
100       41);
101 
102   ExpectInt32(
103       "var n = new Node();"
104       "var g = Object.getOwnPropertyDescriptor("
105       "    n.__proto__.__proto__, 'firstChildRaw')['get'];"
106       "try {"
107       "  var f = { firstChildRaw: '51' };"
108       "  g.apply(f);"
109       "} catch(e) {"
110       "  31415;"
111       "}",
112       31415);
113 }
114