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