Line data Source code
1 : // Copyright 2017 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 "include/v8.h"
6 : #include "src/api.h"
7 : #include "src/objects-inl.h"
8 : #include "test/unittests/test-utils.h"
9 : #include "testing/gtest/include/gtest/gtest.h"
10 :
11 : namespace v8 {
12 : namespace {
13 :
14 : using ObjectTest = TestWithContext;
15 :
16 0 : void accessor_name_getter_callback(Local<Name>,
17 0 : const PropertyCallbackInfo<Value>&) {}
18 :
19 13159 : TEST_F(ObjectTest, SetAccessorWhenUnconfigurablePropAlreadyDefined) {
20 1 : TryCatch try_catch(isolate());
21 :
22 1 : Local<Object> global = context()->Global();
23 : Local<String> property_name =
24 : String::NewFromUtf8(isolate(), "foo", NewStringType::kNormal)
25 1 : .ToLocalChecked();
26 :
27 2 : PropertyDescriptor prop_desc;
28 1 : prop_desc.set_configurable(false);
29 2 : global->DefineProperty(context(), property_name, prop_desc).ToChecked();
30 :
31 : Maybe<bool> result = global->SetAccessor(context(), property_name,
32 1 : accessor_name_getter_callback);
33 2 : ASSERT_TRUE(result.IsJust());
34 2 : ASSERT_FALSE(result.FromJust());
35 3 : ASSERT_FALSE(try_catch.HasCaught());
36 : }
37 :
38 : using LapContextTest = TestWithIsolate;
39 :
40 : // TODO(yukishiino): Enable this unittest once
41 : // PropertyAccessInfo::accessor_holder() gets supported. Currently we're using
42 : // PropertyAccessInfo::holder(), which doesn't return the accessor holder.
43 13155 : TEST_F(LapContextTest, DISABLED_CurrentContextInLazyAccessorOnPrototype) {
44 : // The receiver object is created in |receiver_context|, but its prototype
45 : // object is created in |prototype_context|, and the property is accessed
46 : // from |caller_context|.
47 0 : Local<Context> receiver_context = Context::New(isolate());
48 0 : Local<Context> prototype_context = Context::New(isolate());
49 0 : Local<Context> caller_context = Context::New(isolate());
50 :
51 : static int call_count; // The number of calls of the accessor callback.
52 0 : call_count = 0;
53 :
54 0 : Local<FunctionTemplate> function_template = FunctionTemplate::New(isolate());
55 0 : Local<Signature> signature = Signature::New(isolate(), function_template);
56 : Local<String> property_key =
57 : String::NewFromUtf8(isolate(), "property", NewStringType::kNormal)
58 0 : .ToLocalChecked();
59 : Local<FunctionTemplate> get_or_set = FunctionTemplate::New(
60 : isolate(),
61 0 : [](const FunctionCallbackInfo<Value>& info) {
62 0 : ++call_count;
63 : Local<Context> prototype_context = *reinterpret_cast<Local<Context>*>(
64 0 : info.Data().As<External>()->Value());
65 0 : EXPECT_EQ(prototype_context, info.GetIsolate()->GetCurrentContext());
66 0 : },
67 0 : External::New(isolate(), &prototype_context), signature);
68 0 : function_template->PrototypeTemplate()->SetAccessorProperty(
69 0 : property_key, get_or_set, get_or_set);
70 :
71 : // |object| is created in |receiver_context|, and |prototype| is created
72 : // in |prototype_context|. And then, object.__proto__ = prototype.
73 : Local<Function> interface_for_receiver =
74 0 : function_template->GetFunction(receiver_context).ToLocalChecked();
75 : Local<Function> interface_for_prototype =
76 0 : function_template->GetFunction(prototype_context).ToLocalChecked();
77 : Local<String> prototype_key =
78 : String::NewFromUtf8(isolate(), "prototype", NewStringType::kNormal)
79 0 : .ToLocalChecked();
80 : Local<Object> prototype =
81 0 : interface_for_prototype->Get(caller_context, prototype_key)
82 0 : .ToLocalChecked()
83 : .As<Object>();
84 : Local<Object> object =
85 : interface_for_receiver->NewInstance(receiver_context).ToLocalChecked();
86 0 : object->SetPrototype(caller_context, prototype).ToChecked();
87 0 : EXPECT_EQ(receiver_context, object->CreationContext());
88 0 : EXPECT_EQ(prototype_context, prototype->CreationContext());
89 :
90 0 : EXPECT_EQ(0, call_count);
91 0 : object->Get(caller_context, property_key).ToLocalChecked();
92 0 : EXPECT_EQ(1, call_count);
93 0 : object->Set(caller_context, property_key, Null(isolate())).ToChecked();
94 0 : EXPECT_EQ(2, call_count);
95 :
96 : // Test with a compiled version.
97 : Local<String> object_key =
98 : String::NewFromUtf8(isolate(), "object", NewStringType::kNormal)
99 0 : .ToLocalChecked();
100 0 : caller_context->Global()->Set(caller_context, object_key, object).ToChecked();
101 : const char script[] =
102 : "function f() { object.property; object.property = 0; } "
103 : "f(); f(); "
104 : "%OptimizeFunctionOnNextCall(f); "
105 0 : "f();";
106 : Context::Scope scope(caller_context);
107 0 : internal::FLAG_allow_natives_syntax = true;
108 : Script::Compile(
109 : caller_context,
110 : String::NewFromUtf8(isolate(), script, v8::NewStringType::kNormal)
111 0 : .ToLocalChecked())
112 0 : .ToLocalChecked()
113 : ->Run(caller_context)
114 0 : .ToLocalChecked();
115 0 : EXPECT_EQ(8, call_count);
116 0 : }
117 :
118 13159 : TEST_F(LapContextTest, CurrentContextInLazyAccessorOnPlatformObject) {
119 1 : Local<Context> receiver_context = Context::New(isolate());
120 1 : Local<Context> caller_context = Context::New(isolate());
121 :
122 : static int call_count; // The number of calls of the accessor callback.
123 1 : call_count = 0;
124 :
125 1 : Local<FunctionTemplate> function_template = FunctionTemplate::New(isolate());
126 1 : Local<Signature> signature = Signature::New(isolate(), function_template);
127 : Local<String> property_key =
128 : String::NewFromUtf8(isolate(), "property", NewStringType::kNormal)
129 1 : .ToLocalChecked();
130 : Local<FunctionTemplate> get_or_set = FunctionTemplate::New(
131 : isolate(),
132 32 : [](const FunctionCallbackInfo<Value>& info) {
133 8 : ++call_count;
134 : Local<Context> receiver_context = *reinterpret_cast<Local<Context>*>(
135 8 : info.Data().As<External>()->Value());
136 16 : EXPECT_EQ(receiver_context, info.GetIsolate()->GetCurrentContext());
137 16 : },
138 2 : External::New(isolate(), &receiver_context), signature);
139 2 : function_template->InstanceTemplate()->SetAccessorProperty(
140 2 : property_key, get_or_set, get_or_set);
141 :
142 : Local<Function> interface =
143 1 : function_template->GetFunction(receiver_context).ToLocalChecked();
144 : Local<Object> object =
145 : interface->NewInstance(receiver_context).ToLocalChecked();
146 :
147 2 : EXPECT_EQ(0, call_count);
148 2 : object->Get(caller_context, property_key).ToLocalChecked();
149 2 : EXPECT_EQ(1, call_count);
150 2 : object->Set(caller_context, property_key, Null(isolate())).ToChecked();
151 2 : EXPECT_EQ(2, call_count);
152 :
153 : // Test with a compiled version.
154 : Local<String> object_key =
155 : String::NewFromUtf8(isolate(), "object", NewStringType::kNormal)
156 1 : .ToLocalChecked();
157 3 : caller_context->Global()->Set(caller_context, object_key, object).ToChecked();
158 : const char script[] =
159 : "function f() { object.property; object.property = 0; } "
160 : "f(); f(); "
161 : "%OptimizeFunctionOnNextCall(f); "
162 1 : "f();";
163 : Context::Scope scope(caller_context);
164 1 : internal::FLAG_allow_natives_syntax = true;
165 : Script::Compile(
166 : caller_context,
167 : String::NewFromUtf8(isolate(), script, v8::NewStringType::kNormal)
168 1 : .ToLocalChecked())
169 1 : .ToLocalChecked()
170 : ->Run(caller_context)
171 1 : .ToLocalChecked();
172 2 : EXPECT_EQ(8, call_count);
173 1 : }
174 :
175 13159 : TEST_F(LapContextTest, CurrentContextInLazyAccessorOnInterface) {
176 1 : Local<Context> interface_context = Context::New(isolate());
177 1 : Local<Context> caller_context = Context::New(isolate());
178 :
179 : static int call_count; // The number of calls of the accessor callback.
180 1 : call_count = 0;
181 :
182 1 : Local<FunctionTemplate> function_template = FunctionTemplate::New(isolate());
183 : Local<String> property_key =
184 : String::NewFromUtf8(isolate(), "property", NewStringType::kNormal)
185 1 : .ToLocalChecked();
186 : Local<FunctionTemplate> get_or_set = FunctionTemplate::New(
187 : isolate(),
188 32 : [](const FunctionCallbackInfo<Value>& info) {
189 8 : ++call_count;
190 : Local<Context> interface_context = *reinterpret_cast<Local<Context>*>(
191 8 : info.Data().As<External>()->Value());
192 16 : EXPECT_EQ(interface_context, info.GetIsolate()->GetCurrentContext());
193 16 : },
194 2 : External::New(isolate(), &interface_context), Local<Signature>());
195 1 : function_template->SetAccessorProperty(property_key, get_or_set, get_or_set);
196 :
197 : Local<Function> interface =
198 1 : function_template->GetFunction(interface_context).ToLocalChecked();
199 :
200 2 : EXPECT_EQ(0, call_count);
201 2 : interface->Get(caller_context, property_key).ToLocalChecked();
202 2 : EXPECT_EQ(1, call_count);
203 2 : interface->Set(caller_context, property_key, Null(isolate())).ToChecked();
204 2 : EXPECT_EQ(2, call_count);
205 :
206 : // Test with a compiled version.
207 : Local<String> interface_key =
208 : String::NewFromUtf8(isolate(), "Interface", NewStringType::kNormal)
209 1 : .ToLocalChecked();
210 : caller_context->Global()
211 2 : ->Set(caller_context, interface_key, interface)
212 2 : .ToChecked();
213 : const char script[] =
214 : "function f() { Interface.property; Interface.property = 0; } "
215 : "f(); f(); "
216 : "%OptimizeFunctionOnNextCall(f); "
217 1 : "f();";
218 : Context::Scope scope(caller_context);
219 1 : internal::FLAG_allow_natives_syntax = true;
220 : Script::Compile(
221 : caller_context,
222 : String::NewFromUtf8(isolate(), script, v8::NewStringType::kNormal)
223 1 : .ToLocalChecked())
224 1 : .ToLocalChecked()
225 : ->Run(caller_context)
226 1 : .ToLocalChecked();
227 2 : EXPECT_EQ(8, call_count);
228 1 : }
229 :
230 : } // namespace
231 7893 : } // namespace v8
|