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 13 static void CppAccessor42(const v8::FunctionCallbackInfo<v8::Value>& info) { 14 info.GetReturnValue().Set(42); 15 } 16 17 18 static void CppAccessor41(const v8::FunctionCallbackInfo<v8::Value>& info) { 19 info.GetReturnValue().Set(41); 20 } 21 22 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 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