Line data Source code
1 : // Copyright 2012 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 "src/accessors.h"
6 :
7 : #include "src/api-inl.h"
8 : #include "src/contexts.h"
9 : #include "src/counters.h"
10 : #include "src/deoptimizer.h"
11 : #include "src/execution.h"
12 : #include "src/field-index-inl.h"
13 : #include "src/frames-inl.h"
14 : #include "src/heap/factory.h"
15 : #include "src/isolate-inl.h"
16 : #include "src/messages.h"
17 : #include "src/objects/api-callbacks.h"
18 : #include "src/objects/js-array-inl.h"
19 : #include "src/objects/module-inl.h"
20 : #include "src/property-details.h"
21 : #include "src/prototype.h"
22 :
23 : namespace v8 {
24 : namespace internal {
25 :
26 31014 : Handle<AccessorInfo> Accessors::MakeAccessor(
27 : Isolate* isolate, Handle<Name> name, AccessorNameGetterCallback getter,
28 : AccessorNameBooleanSetterCallback setter) {
29 : Factory* factory = isolate->factory();
30 31014 : Handle<AccessorInfo> info = factory->NewAccessorInfo();
31 31014 : info->set_all_can_read(false);
32 31014 : info->set_all_can_write(false);
33 31014 : info->set_is_special_data_property(true);
34 31014 : info->set_is_sloppy(false);
35 31014 : info->set_replace_on_access(false);
36 31014 : info->set_getter_side_effect_type(SideEffectType::kHasSideEffect);
37 31014 : info->set_setter_side_effect_type(SideEffectType::kHasSideEffect);
38 31014 : name = factory->InternalizeName(name);
39 31014 : info->set_name(*name);
40 31014 : Handle<Object> get = v8::FromCData(isolate, getter);
41 31014 : if (setter == nullptr) setter = &ReconfigureToDataProperty;
42 31014 : Handle<Object> set = v8::FromCData(isolate, setter);
43 31014 : info->set_getter(*get);
44 31014 : info->set_setter(*set);
45 31014 : Address redirected = info->redirected_getter();
46 31014 : if (redirected != kNullAddress) {
47 31014 : Handle<Object> js_get = v8::FromCData(isolate, redirected);
48 31014 : info->set_js_getter(*js_get);
49 : }
50 31014 : return info;
51 : }
52 :
53 : static V8_INLINE bool CheckForName(Isolate* isolate, Handle<Name> name,
54 : Handle<String> property_name, int offset,
55 : FieldIndex::Encoding encoding,
56 : FieldIndex* index) {
57 71160 : if (Name::Equals(isolate, name, property_name)) {
58 61848 : *index = FieldIndex::ForInObjectOffset(offset, encoding);
59 : return true;
60 : }
61 : return false;
62 : }
63 :
64 :
65 : // Returns true for properties that are accessors to object fields.
66 : // If true, *object_offset contains offset of object field.
67 260910 : bool Accessors::IsJSObjectFieldAccessor(Isolate* isolate, Handle<Map> map,
68 : Handle<Name> name, FieldIndex* index) {
69 260910 : switch (map->instance_type()) {
70 : case JS_ARRAY_TYPE:
71 : return CheckForName(isolate, name, isolate->factory()->length_string(),
72 71027 : JSArray::kLengthOffset, FieldIndex::kTagged, index);
73 : default:
74 189885 : if (map->instance_type() < FIRST_NONSTRING_TYPE) {
75 : return CheckForName(isolate, name, isolate->factory()->length_string(),
76 135 : String::kLengthOffset, FieldIndex::kWord32, index);
77 : }
78 :
79 : return false;
80 : }
81 : }
82 :
83 : V8_WARN_UNUSED_RESULT MaybeHandle<Object>
84 16601 : Accessors::ReplaceAccessorWithDataProperty(Handle<Object> receiver,
85 : Handle<JSObject> holder,
86 : Handle<Name> name,
87 : Handle<Object> value) {
88 : LookupIterator it(receiver, name, holder,
89 : LookupIterator::OWN_SKIP_INTERCEPTOR);
90 : // Skip any access checks we might hit. This accessor should never hit in a
91 : // situation where the caller does not have access.
92 16601 : if (it.state() == LookupIterator::ACCESS_CHECK) {
93 0 : CHECK(it.HasAccess());
94 0 : it.Next();
95 : }
96 : DCHECK(holder.is_identical_to(it.GetHolder<JSObject>()));
97 16601 : CHECK_EQ(LookupIterator::ACCESSOR, it.state());
98 16601 : it.ReconfigureDataProperty(value, it.property_attributes());
99 16601 : return value;
100 : }
101 :
102 :
103 : //
104 : // Accessors::ReconfigureToDataProperty
105 : //
106 1534 : void Accessors::ReconfigureToDataProperty(
107 : v8::Local<v8::Name> key, v8::Local<v8::Value> val,
108 : const v8::PropertyCallbackInfo<v8::Boolean>& info) {
109 : i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
110 : RuntimeCallTimerScope stats_scope(
111 1534 : isolate, RuntimeCallCounterId::kReconfigureToDataProperty);
112 : HandleScope scope(isolate);
113 : Handle<Object> receiver = Utils::OpenHandle(*info.This());
114 : Handle<JSObject> holder =
115 1534 : Handle<JSObject>::cast(Utils::OpenHandle(*info.Holder()));
116 1534 : Handle<Name> name = Utils::OpenHandle(*key);
117 1534 : Handle<Object> value = Utils::OpenHandle(*val);
118 : MaybeHandle<Object> result =
119 1534 : Accessors::ReplaceAccessorWithDataProperty(receiver, holder, name, value);
120 1534 : if (result.is_null()) {
121 0 : isolate->OptionalRescheduleException(false);
122 : } else {
123 : info.GetReturnValue().Set(true);
124 : }
125 1534 : }
126 :
127 :
128 : //
129 : // Accessors::ArgumentsIterator
130 : //
131 :
132 :
133 6509 : void Accessors::ArgumentsIteratorGetter(
134 : v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
135 : i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
136 : DisallowHeapAllocation no_allocation;
137 : HandleScope scope(isolate);
138 13018 : Object result = isolate->native_context()->array_values_iterator();
139 : info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(result, isolate)));
140 6509 : }
141 :
142 56 : Handle<AccessorInfo> Accessors::MakeArgumentsIteratorInfo(Isolate* isolate) {
143 : Handle<Name> name = isolate->factory()->iterator_symbol();
144 56 : return MakeAccessor(isolate, name, &ArgumentsIteratorGetter, nullptr);
145 : }
146 :
147 :
148 : //
149 : // Accessors::ArrayLength
150 : //
151 :
152 :
153 132770 : void Accessors::ArrayLengthGetter(
154 : v8::Local<v8::Name> name,
155 : const v8::PropertyCallbackInfo<v8::Value>& info) {
156 : i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
157 : RuntimeCallTimerScope timer(isolate,
158 132770 : RuntimeCallCounterId::kArrayLengthGetter);
159 : DisallowHeapAllocation no_allocation;
160 : HandleScope scope(isolate);
161 : JSArray holder = JSArray::cast(*Utils::OpenHandle(*info.Holder()));
162 : Object result = holder->length();
163 : info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(result, isolate)));
164 132771 : }
165 :
166 470672 : void Accessors::ArrayLengthSetter(
167 : v8::Local<v8::Name> name, v8::Local<v8::Value> val,
168 : const v8::PropertyCallbackInfo<v8::Boolean>& info) {
169 : i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
170 : RuntimeCallTimerScope timer(isolate,
171 470672 : RuntimeCallCounterId::kArrayLengthSetter);
172 : HandleScope scope(isolate);
173 :
174 : DCHECK(Utils::OpenHandle(*name)->SameValue(
175 : ReadOnlyRoots(isolate).length_string()));
176 :
177 : Handle<JSReceiver> object = Utils::OpenHandle(*info.Holder());
178 : Handle<JSArray> array = Handle<JSArray>::cast(object);
179 470672 : Handle<Object> length_obj = Utils::OpenHandle(*val);
180 :
181 470672 : bool was_readonly = JSArray::HasReadOnlyLength(array);
182 :
183 470672 : uint32_t length = 0;
184 470672 : if (!JSArray::AnythingToArrayLength(isolate, length_obj, &length)) {
185 153 : isolate->OptionalRescheduleException(false);
186 153 : return;
187 : }
188 :
189 470537 : if (!was_readonly && V8_UNLIKELY(JSArray::HasReadOnlyLength(array)) &&
190 18 : length != array->length()->Number()) {
191 : // AnythingToArrayLength() may have called setter re-entrantly and modified
192 : // its property descriptor. Don't perform this check if "length" was
193 : // previously readonly, as this may have been called during
194 : // DefineOwnPropertyIgnoreAttributes().
195 18 : if (info.ShouldThrowOnError()) {
196 : Factory* factory = isolate->factory();
197 18 : isolate->Throw(*factory->NewTypeError(
198 : MessageTemplate::kStrictReadOnlyProperty, Utils::OpenHandle(*name),
199 27 : i::Object::TypeOf(isolate, object), object));
200 9 : isolate->OptionalRescheduleException(false);
201 : } else {
202 : info.GetReturnValue().Set(false);
203 : }
204 : return;
205 : }
206 :
207 470501 : JSArray::SetLength(array, length);
208 :
209 470501 : uint32_t actual_new_len = 0;
210 941002 : CHECK(array->length()->ToArrayLength(&actual_new_len));
211 : // Fail if there were non-deletable elements.
212 470501 : if (actual_new_len != length) {
213 63 : if (info.ShouldThrowOnError()) {
214 : Factory* factory = isolate->factory();
215 54 : isolate->Throw(*factory->NewTypeError(
216 : MessageTemplate::kStrictDeleteProperty,
217 81 : factory->NewNumberFromUint(actual_new_len - 1), array));
218 27 : isolate->OptionalRescheduleException(false);
219 : } else {
220 : info.GetReturnValue().Set(false);
221 : }
222 : } else {
223 : info.GetReturnValue().Set(true);
224 : }
225 : }
226 :
227 56 : Handle<AccessorInfo> Accessors::MakeArrayLengthInfo(Isolate* isolate) {
228 : return MakeAccessor(isolate, isolate->factory()->length_string(),
229 56 : &ArrayLengthGetter, &ArrayLengthSetter);
230 : }
231 :
232 : //
233 : // Accessors::ModuleNamespaceEntry
234 : //
235 :
236 31235 : void Accessors::ModuleNamespaceEntryGetter(
237 : v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
238 : i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
239 : HandleScope scope(isolate);
240 : JSModuleNamespace holder =
241 31235 : JSModuleNamespace::cast(*Utils::OpenHandle(*info.Holder()));
242 : Handle<Object> result;
243 31235 : if (!holder
244 62470 : ->GetExport(isolate, Handle<String>::cast(Utils::OpenHandle(*name)))
245 : .ToHandle(&result)) {
246 68 : isolate->OptionalRescheduleException(false);
247 : } else {
248 : info.GetReturnValue().Set(Utils::ToLocal(result));
249 : }
250 31235 : }
251 :
252 45 : void Accessors::ModuleNamespaceEntrySetter(
253 : v8::Local<v8::Name> name, v8::Local<v8::Value> val,
254 : const v8::PropertyCallbackInfo<v8::Boolean>& info) {
255 : i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
256 : HandleScope scope(isolate);
257 : Factory* factory = isolate->factory();
258 : Handle<JSModuleNamespace> holder =
259 : Handle<JSModuleNamespace>::cast(Utils::OpenHandle(*info.Holder()));
260 :
261 45 : if (info.ShouldThrowOnError()) {
262 54 : isolate->Throw(*factory->NewTypeError(
263 : MessageTemplate::kStrictReadOnlyProperty, Utils::OpenHandle(*name),
264 81 : i::Object::TypeOf(isolate, holder), holder));
265 27 : isolate->OptionalRescheduleException(false);
266 : } else {
267 : info.GetReturnValue().Set(false);
268 : }
269 45 : }
270 :
271 30393 : Handle<AccessorInfo> Accessors::MakeModuleNamespaceEntryInfo(
272 : Isolate* isolate, Handle<String> name) {
273 : return MakeAccessor(isolate, name, &ModuleNamespaceEntryGetter,
274 30393 : &ModuleNamespaceEntrySetter);
275 : }
276 :
277 :
278 : //
279 : // Accessors::StringLength
280 : //
281 :
282 145894 : void Accessors::StringLengthGetter(
283 : v8::Local<v8::Name> name,
284 : const v8::PropertyCallbackInfo<v8::Value>& info) {
285 : i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
286 : RuntimeCallTimerScope timer(isolate,
287 145894 : RuntimeCallCounterId::kStringLengthGetter);
288 : DisallowHeapAllocation no_allocation;
289 : HandleScope scope(isolate);
290 :
291 : // We have a slight impedance mismatch between the external API and the way we
292 : // use callbacks internally: Externally, callbacks can only be used with
293 : // v8::Object, but internally we have callbacks on entities which are higher
294 : // in the hierarchy, in this case for String values.
295 :
296 : Object value = *Utils::OpenHandle(*v8::Local<v8::Value>(info.This()));
297 145894 : if (!value->IsString()) {
298 : // Not a string value. That means that we either got a String wrapper or
299 : // a Value with a String wrapper in its prototype chain.
300 : value = JSValue::cast(*Utils::OpenHandle(*info.Holder()))->value();
301 : }
302 : Object result = Smi::FromInt(String::cast(value)->length());
303 : info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(result, isolate)));
304 145894 : }
305 :
306 56 : Handle<AccessorInfo> Accessors::MakeStringLengthInfo(Isolate* isolate) {
307 : return MakeAccessor(isolate, isolate->factory()->length_string(),
308 56 : &StringLengthGetter, nullptr);
309 : }
310 :
311 : //
312 : // Accessors::FunctionPrototype
313 : //
314 :
315 84353 : static Handle<Object> GetFunctionPrototype(Isolate* isolate,
316 : Handle<JSFunction> function) {
317 84353 : if (!function->has_prototype()) {
318 44716 : Handle<Object> proto = isolate->factory()->NewFunctionPrototype(function);
319 44716 : JSFunction::SetPrototype(function, proto);
320 : }
321 168706 : return Handle<Object>(function->prototype(), isolate);
322 : }
323 :
324 84353 : void Accessors::FunctionPrototypeGetter(
325 : v8::Local<v8::Name> name,
326 : const v8::PropertyCallbackInfo<v8::Value>& info) {
327 : i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
328 : RuntimeCallTimerScope timer(isolate,
329 84353 : RuntimeCallCounterId::kFunctionPrototypeGetter);
330 : HandleScope scope(isolate);
331 : Handle<JSFunction> function =
332 84353 : Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
333 : DCHECK(function->has_prototype_property());
334 84353 : Handle<Object> result = GetFunctionPrototype(isolate, function);
335 : info.GetReturnValue().Set(Utils::ToLocal(result));
336 84353 : }
337 :
338 134860 : void Accessors::FunctionPrototypeSetter(
339 : v8::Local<v8::Name> name, v8::Local<v8::Value> val,
340 : const v8::PropertyCallbackInfo<v8::Boolean>& info) {
341 : i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
342 : RuntimeCallTimerScope timer(isolate,
343 134860 : RuntimeCallCounterId::kFunctionPrototypeSetter);
344 : HandleScope scope(isolate);
345 134860 : Handle<Object> value = Utils::OpenHandle(*val);
346 : Handle<JSFunction> object =
347 134860 : Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
348 : DCHECK(object->has_prototype_property());
349 134860 : JSFunction::SetPrototype(object, value);
350 : info.GetReturnValue().Set(true);
351 134860 : }
352 :
353 56 : Handle<AccessorInfo> Accessors::MakeFunctionPrototypeInfo(Isolate* isolate) {
354 : return MakeAccessor(isolate, isolate->factory()->prototype_string(),
355 56 : &FunctionPrototypeGetter, &FunctionPrototypeSetter);
356 : }
357 :
358 :
359 : //
360 : // Accessors::FunctionLength
361 : //
362 :
363 :
364 54014 : void Accessors::FunctionLengthGetter(
365 : v8::Local<v8::Name> name,
366 : const v8::PropertyCallbackInfo<v8::Value>& info) {
367 : i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
368 : RuntimeCallTimerScope timer(isolate,
369 54014 : RuntimeCallCounterId::kFunctionLengthGetter);
370 : HandleScope scope(isolate);
371 : Handle<JSFunction> function =
372 54014 : Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
373 : int length = 0;
374 108028 : if (!JSFunction::GetLength(isolate, function).To(&length)) {
375 382 : isolate->OptionalRescheduleException(false);
376 : }
377 : Handle<Object> result(Smi::FromInt(length), isolate);
378 : info.GetReturnValue().Set(Utils::ToLocal(result));
379 54014 : }
380 :
381 56 : Handle<AccessorInfo> Accessors::MakeFunctionLengthInfo(Isolate* isolate) {
382 : return MakeAccessor(isolate, isolate->factory()->length_string(),
383 56 : &FunctionLengthGetter, &ReconfigureToDataProperty);
384 : }
385 :
386 :
387 : //
388 : // Accessors::FunctionName
389 : //
390 :
391 :
392 112542 : void Accessors::FunctionNameGetter(
393 : v8::Local<v8::Name> name,
394 : const v8::PropertyCallbackInfo<v8::Value>& info) {
395 : i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
396 : HandleScope scope(isolate);
397 : Handle<JSFunction> function =
398 112542 : Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
399 112542 : Handle<Object> result = JSFunction::GetName(isolate, function);
400 : info.GetReturnValue().Set(Utils::ToLocal(result));
401 112542 : }
402 :
403 56 : Handle<AccessorInfo> Accessors::MakeFunctionNameInfo(Isolate* isolate) {
404 : return MakeAccessor(isolate, isolate->factory()->name_string(),
405 56 : &FunctionNameGetter, &ReconfigureToDataProperty);
406 : }
407 :
408 :
409 : //
410 : // Accessors::FunctionArguments
411 : //
412 :
413 : namespace {
414 :
415 2729 : Handle<JSObject> ArgumentsForInlinedFunction(JavaScriptFrame* frame,
416 : int inlined_frame_index) {
417 : Isolate* isolate = frame->isolate();
418 : Factory* factory = isolate->factory();
419 :
420 2729 : TranslatedState translated_values(frame);
421 2729 : translated_values.Prepare(frame->fp());
422 :
423 2729 : int argument_count = 0;
424 : TranslatedFrame* translated_frame =
425 : translated_values.GetArgumentsInfoFromJSFrameIndex(inlined_frame_index,
426 2729 : &argument_count);
427 : TranslatedFrame::iterator iter = translated_frame->begin();
428 :
429 : // Materialize the function.
430 2729 : bool should_deoptimize = iter->IsMaterializedObject();
431 2729 : Handle<JSFunction> function = Handle<JSFunction>::cast(iter->GetValue());
432 : iter++;
433 :
434 : // Skip the receiver.
435 : iter++;
436 2729 : argument_count--;
437 :
438 : Handle<JSObject> arguments =
439 2729 : factory->NewArgumentsObject(function, argument_count);
440 2729 : Handle<FixedArray> array = factory->NewFixedArray(argument_count);
441 17513 : for (int i = 0; i < argument_count; ++i) {
442 : // If we materialize any object, we should deoptimize the frame because we
443 : // might alias an object that was eliminated by escape analysis.
444 7392 : should_deoptimize = should_deoptimize || iter->IsMaterializedObject();
445 7392 : Handle<Object> value = iter->GetValue();
446 7392 : array->set(i, *value);
447 : iter++;
448 : }
449 5458 : arguments->set_elements(*array);
450 :
451 2729 : if (should_deoptimize) {
452 158 : translated_values.StoreMaterializedValuesAndDeopt(frame);
453 : }
454 :
455 : // Return the freshly allocated arguments object.
456 5458 : return arguments;
457 : }
458 :
459 105289 : int FindFunctionInFrame(JavaScriptFrame* frame, Handle<JSFunction> function) {
460 105289 : std::vector<FrameSummary> frames;
461 105289 : frame->Summarize(&frames);
462 159482 : for (size_t i = frames.size(); i != 0; i--) {
463 215624 : if (*frames[i - 1].AsJavaScript().function() == *function) {
464 53619 : return static_cast<int>(i) - 1;
465 : }
466 : }
467 : return -1;
468 : }
469 :
470 64629 : Handle<JSObject> GetFrameArguments(Isolate* isolate,
471 : JavaScriptFrameIterator* it,
472 : int function_index) {
473 : JavaScriptFrame* frame = it->frame();
474 :
475 64629 : if (function_index > 0) {
476 : // The function in question was inlined. Inlined functions have the
477 : // correct number of arguments and no allocated arguments object, so
478 : // we can construct a fresh one by interpreting the function's
479 : // deoptimization input data.
480 2729 : return ArgumentsForInlinedFunction(frame, function_index);
481 : }
482 :
483 : // Find the frame that holds the actual arguments passed to the function.
484 61900 : if (it->frame()->has_adapted_arguments()) {
485 : it->AdvanceOneFrame();
486 : DCHECK(it->frame()->is_arguments_adaptor());
487 : }
488 : frame = it->frame();
489 :
490 : // Get the number of arguments and construct an arguments object
491 : // mirror for the right frame and the underlying function.
492 61900 : const int length = frame->ComputeParametersCount();
493 61900 : Handle<JSFunction> function(frame->function(), isolate);
494 : Handle<JSObject> arguments =
495 61900 : isolate->factory()->NewArgumentsObject(function, length);
496 61900 : Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
497 :
498 : // Copy the parameters to the arguments object.
499 : DCHECK(array->length() == length);
500 334970 : for (int i = 0; i < length; i++) {
501 136535 : Object value = frame->GetParameter(i);
502 136535 : if (value->IsTheHole(isolate)) {
503 : // Generators currently use holes as dummy arguments when resuming. We
504 : // must not leak those.
505 : DCHECK(IsResumableFunction(function->shared()->kind()));
506 : value = ReadOnlyRoots(isolate).undefined_value();
507 : }
508 136535 : array->set(i, value);
509 : }
510 123800 : arguments->set_elements(*array);
511 :
512 : // Return the freshly allocated arguments object.
513 61900 : return arguments;
514 : }
515 :
516 : } // namespace
517 :
518 11010 : Handle<JSObject> Accessors::FunctionGetArguments(JavaScriptFrame* frame,
519 : int inlined_jsframe_index) {
520 : Isolate* isolate = frame->isolate();
521 : Address requested_frame_fp = frame->fp();
522 : // Forward a frame iterator to the requested frame. This is needed because we
523 : // potentially need for advance it to the arguments adaptor frame later.
524 109926 : for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) {
525 109926 : if (it.frame()->fp() != requested_frame_fp) continue;
526 11010 : return GetFrameArguments(isolate, &it, inlined_jsframe_index);
527 : }
528 0 : UNREACHABLE(); // Requested frame not found.
529 : return Handle<JSObject>();
530 : }
531 :
532 :
533 54696 : void Accessors::FunctionArgumentsGetter(
534 : v8::Local<v8::Name> name,
535 : const v8::PropertyCallbackInfo<v8::Value>& info) {
536 : i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
537 : HandleScope scope(isolate);
538 : Handle<JSFunction> function =
539 : Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
540 : Handle<Object> result = isolate->factory()->null_value();
541 54696 : if (!function->shared()->native()) {
542 : // Find the top invocation of the function by traversing frames.
543 106366 : for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) {
544 : JavaScriptFrame* frame = it.frame();
545 105289 : int function_index = FindFunctionInFrame(frame, function);
546 105289 : if (function_index >= 0) {
547 53619 : result = GetFrameArguments(isolate, &it, function_index);
548 53619 : break;
549 : }
550 : }
551 : }
552 : info.GetReturnValue().Set(Utils::ToLocal(result));
553 54696 : }
554 :
555 56 : Handle<AccessorInfo> Accessors::MakeFunctionArgumentsInfo(Isolate* isolate) {
556 : return MakeAccessor(isolate, isolate->factory()->arguments_string(),
557 56 : &FunctionArgumentsGetter, nullptr);
558 : }
559 :
560 :
561 : //
562 : // Accessors::FunctionCaller
563 : //
564 :
565 17332 : static inline bool AllowAccessToFunction(Context current_context,
566 : JSFunction function) {
567 17332 : return current_context->HasSameSecurityTokenAs(function->context());
568 : }
569 :
570 7542 : class FrameFunctionIterator {
571 : public:
572 3771 : explicit FrameFunctionIterator(Isolate* isolate)
573 11313 : : isolate_(isolate), frame_iterator_(isolate), inlined_frame_index_(-1) {
574 : GetFrames();
575 3771 : }
576 :
577 : // Iterate through functions until the first occurrence of 'function'.
578 : // Returns true if one is found, and false if the iterator ends before.
579 3771 : bool Find(Handle<JSFunction> function) {
580 10420 : do {
581 23000 : if (!next().ToHandle(&function_)) return false;
582 : } while (!function_.is_identical_to(function));
583 : return true;
584 : }
585 :
586 : // Iterate through functions until the next non-toplevel one is found.
587 : // Returns true if one is found, and false if the iterator ends before.
588 2691 : bool FindNextNonTopLevel() {
589 4563 : do {
590 9288 : if (!next().ToHandle(&function_)) return false;
591 : } while (function_->shared()->is_toplevel());
592 : return true;
593 : }
594 :
595 : // Iterate through function until the first native or user-provided function
596 : // is found. Functions not defined in user-provided scripts are not visible
597 : // unless directly exposed, in which case the native flag is set on them.
598 : // Returns true if one is found, and false if the iterator ends before.
599 2610 : bool FindFirstNativeOrUserJavaScript() {
600 7731 : while (!function_->shared()->native() &&
601 5121 : !function_->shared()->IsUserJavaScript()) {
602 0 : if (!next().ToHandle(&function_)) return false;
603 : }
604 : return true;
605 : }
606 :
607 : // In case of inlined frames the function could have been materialized from
608 : // deoptimization information. If that is the case we need to make sure that
609 : // subsequent call will see the same function, since we are about to hand out
610 : // the value to JavaScript. Make sure to store the materialized value and
611 : // trigger a deoptimization of the underlying frame.
612 2610 : Handle<JSFunction> MaterializeFunction() {
613 2610 : if (inlined_frame_index_ == 0) return function_;
614 :
615 : JavaScriptFrame* frame = frame_iterator_.frame();
616 45 : TranslatedState translated_values(frame);
617 45 : translated_values.Prepare(frame->fp());
618 :
619 : TranslatedFrame* translated_frame =
620 45 : translated_values.GetFrameFromJSFrameIndex(inlined_frame_index_);
621 : TranslatedFrame::iterator iter = translated_frame->begin();
622 :
623 : // First value is the function.
624 45 : bool should_deoptimize = iter->IsMaterializedObject();
625 45 : Handle<Object> value = iter->GetValue();
626 45 : if (should_deoptimize) {
627 24 : translated_values.StoreMaterializedValuesAndDeopt(frame);
628 : }
629 :
630 : return Handle<JSFunction>::cast(value);
631 : }
632 :
633 : private:
634 16144 : MaybeHandle<JSFunction> next() {
635 : while (true) {
636 16171 : if (inlined_frame_index_ <= 0) {
637 11964 : if (!frame_iterator_.done()) {
638 11910 : frame_iterator_.Advance();
639 : frames_.clear();
640 11910 : inlined_frame_index_ = -1;
641 : GetFrames();
642 : }
643 11964 : if (inlined_frame_index_ == -1) return MaybeHandle<JSFunction>();
644 : }
645 :
646 15010 : --inlined_frame_index_;
647 : Handle<JSFunction> next_function =
648 15010 : frames_[inlined_frame_index_].AsJavaScript().function();
649 : // Skip functions from other origins.
650 30020 : if (!AllowAccessToFunction(isolate_->context(), *next_function)) continue;
651 14983 : return next_function;
652 : }
653 : }
654 : void GetFrames() {
655 : DCHECK_EQ(-1, inlined_frame_index_);
656 15681 : if (frame_iterator_.done()) return;
657 : JavaScriptFrame* frame = frame_iterator_.frame();
658 14520 : frame->Summarize(&frames_);
659 14520 : inlined_frame_index_ = static_cast<int>(frames_.size());
660 : DCHECK_LT(0, inlined_frame_index_);
661 : }
662 : Isolate* isolate_;
663 : Handle<JSFunction> function_;
664 : JavaScriptFrameIterator frame_iterator_;
665 : std::vector<FrameSummary> frames_;
666 : int inlined_frame_index_;
667 : };
668 :
669 :
670 3771 : MaybeHandle<JSFunction> FindCaller(Isolate* isolate,
671 : Handle<JSFunction> function) {
672 3771 : FrameFunctionIterator it(isolate);
673 3771 : if (function->shared()->native()) {
674 0 : return MaybeHandle<JSFunction>();
675 : }
676 : // Find the function from the frames. Return null in case no frame
677 : // corresponding to the given function was found.
678 3771 : if (!it.Find(function)) {
679 1080 : return MaybeHandle<JSFunction>();
680 : }
681 : // Find previously called non-toplevel function.
682 2691 : if (!it.FindNextNonTopLevel()) {
683 81 : return MaybeHandle<JSFunction>();
684 : }
685 : // Find the first user-land JavaScript function (or the entry point into
686 : // native JavaScript builtins in case such a builtin was the caller).
687 2610 : if (!it.FindFirstNativeOrUserJavaScript()) {
688 0 : return MaybeHandle<JSFunction>();
689 : }
690 :
691 : // Materialize the function that the iterator is currently sitting on. Note
692 : // that this might trigger deoptimization in case the function was actually
693 : // materialized. Identity of the function must be preserved because we are
694 : // going to return it to JavaScript after this point.
695 2610 : Handle<JSFunction> caller = it.MaterializeFunction();
696 :
697 : // Censor if the caller is not a sloppy mode function.
698 : // Change from ES5, which used to throw, see:
699 : // https://bugs.ecmascript.org/show_bug.cgi?id=310
700 2610 : if (is_strict(caller->shared()->language_mode())) {
701 288 : return MaybeHandle<JSFunction>();
702 : }
703 : // Don't return caller from another security context.
704 2322 : if (!AllowAccessToFunction(isolate->context(), *caller)) {
705 0 : return MaybeHandle<JSFunction>();
706 : }
707 2322 : return caller;
708 : }
709 :
710 :
711 3771 : void Accessors::FunctionCallerGetter(
712 : v8::Local<v8::Name> name,
713 : const v8::PropertyCallbackInfo<v8::Value>& info) {
714 : i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
715 : HandleScope scope(isolate);
716 : Handle<JSFunction> function =
717 3771 : Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
718 : Handle<Object> result;
719 : MaybeHandle<JSFunction> maybe_caller;
720 3771 : maybe_caller = FindCaller(isolate, function);
721 : Handle<JSFunction> caller;
722 3771 : if (maybe_caller.ToHandle(&caller)) {
723 : result = caller;
724 : } else {
725 : result = isolate->factory()->null_value();
726 : }
727 : info.GetReturnValue().Set(Utils::ToLocal(result));
728 3771 : }
729 :
730 56 : Handle<AccessorInfo> Accessors::MakeFunctionCallerInfo(Isolate* isolate) {
731 : return MakeAccessor(isolate, isolate->factory()->caller_string(),
732 56 : &FunctionCallerGetter, nullptr);
733 : }
734 :
735 :
736 : //
737 : // Accessors::BoundFunctionLength
738 : //
739 :
740 316 : void Accessors::BoundFunctionLengthGetter(
741 : v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
742 : i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
743 : RuntimeCallTimerScope timer(isolate,
744 316 : RuntimeCallCounterId::kBoundFunctionLengthGetter);
745 : HandleScope scope(isolate);
746 : Handle<JSBoundFunction> function =
747 316 : Handle<JSBoundFunction>::cast(Utils::OpenHandle(*info.Holder()));
748 :
749 : int length = 0;
750 632 : if (!JSBoundFunction::GetLength(isolate, function).To(&length)) {
751 0 : isolate->OptionalRescheduleException(false);
752 : return;
753 : }
754 : Handle<Object> result(Smi::FromInt(length), isolate);
755 : info.GetReturnValue().Set(Utils::ToLocal(result));
756 : }
757 :
758 56 : Handle<AccessorInfo> Accessors::MakeBoundFunctionLengthInfo(Isolate* isolate) {
759 : return MakeAccessor(isolate, isolate->factory()->length_string(),
760 56 : &BoundFunctionLengthGetter, &ReconfigureToDataProperty);
761 : }
762 :
763 : //
764 : // Accessors::BoundFunctionName
765 : //
766 :
767 82 : void Accessors::BoundFunctionNameGetter(
768 : v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
769 : i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
770 : RuntimeCallTimerScope timer(isolate,
771 82 : RuntimeCallCounterId::kBoundFunctionNameGetter);
772 : HandleScope scope(isolate);
773 : Handle<JSBoundFunction> function =
774 82 : Handle<JSBoundFunction>::cast(Utils::OpenHandle(*info.Holder()));
775 : Handle<Object> result;
776 164 : if (!JSBoundFunction::GetName(isolate, function).ToHandle(&result)) {
777 0 : isolate->OptionalRescheduleException(false);
778 : return;
779 : }
780 : info.GetReturnValue().Set(Utils::ToLocal(result));
781 : }
782 :
783 56 : Handle<AccessorInfo> Accessors::MakeBoundFunctionNameInfo(Isolate* isolate) {
784 : return MakeAccessor(isolate, isolate->factory()->name_string(),
785 56 : &BoundFunctionNameGetter, &ReconfigureToDataProperty);
786 : }
787 :
788 : //
789 : // Accessors::ErrorStack
790 : //
791 :
792 : namespace {
793 :
794 15177 : MaybeHandle<JSReceiver> ClearInternalStackTrace(Isolate* isolate,
795 : Handle<JSObject> error) {
796 30354 : RETURN_ON_EXCEPTION(
797 : isolate,
798 : Object::SetProperty(
799 : isolate, error, isolate->factory()->stack_trace_symbol(),
800 : isolate->factory()->undefined_value(), StoreOrigin::kMaybeKeyed,
801 : Just(ShouldThrow::kThrowOnError)),
802 : JSReceiver);
803 15177 : return error;
804 : }
805 :
806 15097 : bool IsAccessor(Handle<Object> receiver, Handle<Name> name,
807 : Handle<JSObject> holder) {
808 : LookupIterator it(receiver, name, holder,
809 : LookupIterator::OWN_SKIP_INTERCEPTOR);
810 : // Skip any access checks we might hit. This accessor should never hit in a
811 : // situation where the caller does not have access.
812 15097 : if (it.state() == LookupIterator::ACCESS_CHECK) {
813 0 : CHECK(it.HasAccess());
814 0 : it.Next();
815 : }
816 15097 : return (it.state() == LookupIterator::ACCESSOR);
817 : }
818 :
819 : } // namespace
820 :
821 15222 : void Accessors::ErrorStackGetter(
822 : v8::Local<v8::Name> key, const v8::PropertyCallbackInfo<v8::Value>& info) {
823 : i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
824 : HandleScope scope(isolate);
825 : Handle<JSObject> holder =
826 : Handle<JSObject>::cast(Utils::OpenHandle(*info.Holder()));
827 :
828 : // Retrieve the structured stack trace.
829 :
830 : Handle<Object> stack_trace;
831 : Handle<Symbol> stack_trace_symbol = isolate->factory()->stack_trace_symbol();
832 : MaybeHandle<Object> maybe_stack_trace =
833 15222 : JSObject::GetProperty(isolate, holder, stack_trace_symbol);
834 30444 : if (!maybe_stack_trace.ToHandle(&stack_trace) ||
835 : stack_trace->IsUndefined(isolate)) {
836 : Handle<Object> result = isolate->factory()->undefined_value();
837 : info.GetReturnValue().Set(Utils::ToLocal(result));
838 : return;
839 : }
840 :
841 : // Format it, clear the internal structured trace and reconfigure as a data
842 : // property.
843 :
844 : Handle<Object> formatted_stack_trace;
845 30426 : if (!ErrorUtils::FormatStackTrace(isolate, holder, stack_trace)
846 : .ToHandle(&formatted_stack_trace)) {
847 116 : isolate->OptionalRescheduleException(false);
848 116 : return;
849 : }
850 :
851 15097 : MaybeHandle<Object> result = ClearInternalStackTrace(isolate, holder);
852 15097 : if (result.is_null()) {
853 0 : isolate->OptionalRescheduleException(false);
854 0 : return;
855 : }
856 :
857 : // If stack is still an accessor (this could have changed in the meantime
858 : // since FormatStackTrace can execute arbitrary JS), replace it with a data
859 : // property.
860 : Handle<Object> receiver =
861 15097 : Utils::OpenHandle(*v8::Local<v8::Value>(info.This()));
862 15097 : Handle<Name> name = Utils::OpenHandle(*key);
863 15097 : if (IsAccessor(receiver, name, holder)) {
864 : result = Accessors::ReplaceAccessorWithDataProperty(receiver, holder, name,
865 15052 : formatted_stack_trace);
866 15052 : if (result.is_null()) {
867 0 : isolate->OptionalRescheduleException(false);
868 0 : return;
869 : }
870 : } else {
871 : // The stack property has been modified in the meantime.
872 90 : if (!JSObject::GetProperty(isolate, holder, name)
873 : .ToHandle(&formatted_stack_trace)) {
874 0 : isolate->OptionalRescheduleException(false);
875 0 : return;
876 : }
877 : }
878 :
879 : v8::Local<v8::Value> value = Utils::ToLocal(formatted_stack_trace);
880 : info.GetReturnValue().Set(value);
881 : }
882 :
883 80 : void Accessors::ErrorStackSetter(
884 : v8::Local<v8::Name> name, v8::Local<v8::Value> val,
885 : const v8::PropertyCallbackInfo<v8::Boolean>& info) {
886 : i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
887 : HandleScope scope(isolate);
888 : Handle<JSObject> obj = Handle<JSObject>::cast(
889 : Utils::OpenHandle(*v8::Local<v8::Value>(info.This())));
890 :
891 : // Clear internal properties to avoid memory leaks.
892 : Handle<Symbol> stack_trace_symbol = isolate->factory()->stack_trace_symbol();
893 160 : if (JSReceiver::HasOwnProperty(obj, stack_trace_symbol).FromMaybe(false)) {
894 80 : ClearInternalStackTrace(isolate, obj);
895 : }
896 :
897 80 : Accessors::ReconfigureToDataProperty(name, val, info);
898 80 : }
899 :
900 56 : Handle<AccessorInfo> Accessors::MakeErrorStackInfo(Isolate* isolate) {
901 : return MakeAccessor(isolate, isolate->factory()->stack_string(),
902 56 : &ErrorStackGetter, &ErrorStackSetter);
903 : }
904 :
905 : } // namespace internal
906 120216 : } // namespace v8
|