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 31994 : Handle<AccessorInfo> Accessors::MakeAccessor(
27 : Isolate* isolate, Handle<Name> name, AccessorNameGetterCallback getter,
28 : AccessorNameBooleanSetterCallback setter) {
29 : Factory* factory = isolate->factory();
30 31994 : Handle<AccessorInfo> info = factory->NewAccessorInfo();
31 31994 : info->set_all_can_read(false);
32 31994 : info->set_all_can_write(false);
33 31994 : info->set_is_special_data_property(true);
34 31994 : info->set_is_sloppy(false);
35 31994 : info->set_replace_on_access(false);
36 31994 : info->set_getter_side_effect_type(SideEffectType::kHasSideEffect);
37 31994 : info->set_setter_side_effect_type(SideEffectType::kHasSideEffect);
38 31994 : name = factory->InternalizeName(name);
39 31994 : info->set_name(*name);
40 31994 : Handle<Object> get = v8::FromCData(isolate, getter);
41 31994 : if (setter == nullptr) setter = &ReconfigureToDataProperty;
42 31994 : Handle<Object> set = v8::FromCData(isolate, setter);
43 31994 : info->set_getter(*get);
44 31994 : info->set_setter(*set);
45 31994 : Address redirected = info->redirected_getter();
46 31994 : if (redirected != kNullAddress) {
47 31014 : Handle<Object> js_get = v8::FromCData(isolate, redirected);
48 31014 : info->set_js_getter(*js_get);
49 : }
50 31994 : 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 75228 : if (Name::Equals(isolate, name, property_name)) {
58 65372 : *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 265480 : bool Accessors::IsJSObjectFieldAccessor(Isolate* isolate, Handle<Map> map,
68 : Handle<Name> name, FieldIndex* index) {
69 265480 : switch (map->instance_type()) {
70 : case JS_ARRAY_TYPE:
71 : return CheckForName(isolate, name, isolate->factory()->length_string(),
72 75101 : JSArray::kLengthOffset, FieldIndex::kTagged, index);
73 : default:
74 190387 : 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 1469 : 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 1469 : 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 1469 : CHECK_EQ(LookupIterator::ACCESSOR, it.state());
98 1469 : it.ReconfigureDataProperty(value, it.property_attributes());
99 1469 : return value;
100 : }
101 :
102 :
103 : //
104 : // Accessors::ReconfigureToDataProperty
105 : //
106 1454 : 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 1454 : isolate, RuntimeCallCounterId::kReconfigureToDataProperty);
112 : HandleScope scope(isolate);
113 : Handle<Object> receiver = Utils::OpenHandle(*info.This());
114 : Handle<JSObject> holder =
115 1454 : Handle<JSObject>::cast(Utils::OpenHandle(*info.Holder()));
116 1454 : Handle<Name> name = Utils::OpenHandle(*key);
117 1454 : Handle<Object> value = Utils::OpenHandle(*val);
118 : MaybeHandle<Object> result =
119 1454 : Accessors::ReplaceAccessorWithDataProperty(receiver, holder, name, value);
120 1454 : if (result.is_null()) {
121 0 : isolate->OptionalRescheduleException(false);
122 : } else {
123 : info.GetReturnValue().Set(true);
124 : }
125 1454 : }
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 136397 : 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 136397 : 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 136396 : }
165 :
166 476405 : 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 476405 : 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 476405 : Handle<Object> length_obj = Utils::OpenHandle(*val);
180 :
181 476405 : bool was_readonly = JSArray::HasReadOnlyLength(array);
182 :
183 476405 : uint32_t length = 0;
184 476405 : if (!JSArray::AnythingToArrayLength(isolate, length_obj, &length)) {
185 153 : isolate->OptionalRescheduleException(false);
186 153 : return;
187 : }
188 :
189 476270 : 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 476234 : JSArray::SetLength(array, length);
208 :
209 476234 : uint32_t actual_new_len = 0;
210 952468 : CHECK(array->length()->ToArrayLength(&actual_new_len));
211 : // Fail if there were non-deletable elements.
212 476234 : if (actual_new_len != length) {
213 67 : 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 146143 : 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 146143 : 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 146143 : 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 146143 : }
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 85356 : static Handle<Object> GetFunctionPrototype(Isolate* isolate,
316 : Handle<JSFunction> function) {
317 85356 : if (!function->has_prototype()) {
318 45598 : Handle<Object> proto = isolate->factory()->NewFunctionPrototype(function);
319 45598 : JSFunction::SetPrototype(function, proto);
320 : }
321 170712 : return Handle<Object>(function->prototype(), isolate);
322 : }
323 :
324 85356 : 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 85356 : RuntimeCallCounterId::kFunctionPrototypeGetter);
330 : HandleScope scope(isolate);
331 : Handle<JSFunction> function =
332 85356 : Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
333 : DCHECK(function->has_prototype_property());
334 85356 : Handle<Object> result = GetFunctionPrototype(isolate, function);
335 : info.GetReturnValue().Set(Utils::ToLocal(result));
336 85356 : }
337 :
338 135085 : 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 135085 : RuntimeCallCounterId::kFunctionPrototypeSetter);
344 : HandleScope scope(isolate);
345 135085 : Handle<Object> value = Utils::OpenHandle(*val);
346 : Handle<JSFunction> object =
347 135085 : Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
348 : DCHECK(object->has_prototype_property());
349 135085 : JSFunction::SetPrototype(object, value);
350 : info.GetReturnValue().Set(true);
351 135085 : }
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 53409 : 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 53409 : RuntimeCallCounterId::kFunctionLengthGetter);
370 : HandleScope scope(isolate);
371 : Handle<JSFunction> function =
372 : Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
373 : int length = function->length();
374 : Handle<Object> result(Smi::FromInt(length), isolate);
375 : info.GetReturnValue().Set(Utils::ToLocal(result));
376 53409 : }
377 :
378 56 : Handle<AccessorInfo> Accessors::MakeFunctionLengthInfo(Isolate* isolate) {
379 : return MakeAccessor(isolate, isolate->factory()->length_string(),
380 56 : &FunctionLengthGetter, &ReconfigureToDataProperty);
381 : }
382 :
383 :
384 : //
385 : // Accessors::FunctionName
386 : //
387 :
388 :
389 113047 : void Accessors::FunctionNameGetter(
390 : v8::Local<v8::Name> name,
391 : const v8::PropertyCallbackInfo<v8::Value>& info) {
392 : i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
393 : HandleScope scope(isolate);
394 : Handle<JSFunction> function =
395 113047 : Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
396 113047 : Handle<Object> result = JSFunction::GetName(isolate, function);
397 : info.GetReturnValue().Set(Utils::ToLocal(result));
398 113047 : }
399 :
400 56 : Handle<AccessorInfo> Accessors::MakeFunctionNameInfo(Isolate* isolate) {
401 : return MakeAccessor(isolate, isolate->factory()->name_string(),
402 56 : &FunctionNameGetter, &ReconfigureToDataProperty);
403 : }
404 :
405 :
406 : //
407 : // Accessors::FunctionArguments
408 : //
409 :
410 : namespace {
411 :
412 2694 : Handle<JSObject> ArgumentsForInlinedFunction(JavaScriptFrame* frame,
413 : int inlined_frame_index) {
414 : Isolate* isolate = frame->isolate();
415 : Factory* factory = isolate->factory();
416 :
417 2694 : TranslatedState translated_values(frame);
418 2694 : translated_values.Prepare(frame->fp());
419 :
420 2694 : int argument_count = 0;
421 : TranslatedFrame* translated_frame =
422 : translated_values.GetArgumentsInfoFromJSFrameIndex(inlined_frame_index,
423 2694 : &argument_count);
424 : TranslatedFrame::iterator iter = translated_frame->begin();
425 :
426 : // Materialize the function.
427 2694 : bool should_deoptimize = iter->IsMaterializedObject();
428 2694 : Handle<JSFunction> function = Handle<JSFunction>::cast(iter->GetValue());
429 : iter++;
430 :
431 : // Skip the receiver.
432 : iter++;
433 2694 : argument_count--;
434 :
435 : Handle<JSObject> arguments =
436 2694 : factory->NewArgumentsObject(function, argument_count);
437 2694 : Handle<FixedArray> array = factory->NewFixedArray(argument_count);
438 17996 : for (int i = 0; i < argument_count; ++i) {
439 : // If we materialize any object, we should deoptimize the frame because we
440 : // might alias an object that was eliminated by escape analysis.
441 7651 : should_deoptimize = should_deoptimize || iter->IsMaterializedObject();
442 7651 : Handle<Object> value = iter->GetValue();
443 7651 : array->set(i, *value);
444 : iter++;
445 : }
446 5388 : arguments->set_elements(*array);
447 :
448 2694 : if (should_deoptimize) {
449 158 : translated_values.StoreMaterializedValuesAndDeopt(frame);
450 : }
451 :
452 : // Return the freshly allocated arguments object.
453 5388 : return arguments;
454 : }
455 :
456 105666 : int FindFunctionInFrame(JavaScriptFrame* frame, Handle<JSFunction> function) {
457 105666 : std::vector<FrameSummary> frames;
458 105666 : frame->Summarize(&frames);
459 160003 : for (size_t i = frames.size(); i != 0; i--) {
460 215912 : if (*frames[i - 1].AsJavaScript().function() == *function) {
461 53619 : return static_cast<int>(i) - 1;
462 : }
463 : }
464 : return -1;
465 : }
466 :
467 64647 : Handle<JSObject> GetFrameArguments(Isolate* isolate,
468 : JavaScriptFrameIterator* it,
469 : int function_index) {
470 : JavaScriptFrame* frame = it->frame();
471 :
472 64647 : if (function_index > 0) {
473 : // The function in question was inlined. Inlined functions have the
474 : // correct number of arguments and no allocated arguments object, so
475 : // we can construct a fresh one by interpreting the function's
476 : // deoptimization input data.
477 2694 : return ArgumentsForInlinedFunction(frame, function_index);
478 : }
479 :
480 : // Find the frame that holds the actual arguments passed to the function.
481 61953 : if (it->frame()->has_adapted_arguments()) {
482 : it->AdvanceOneFrame();
483 : DCHECK(it->frame()->is_arguments_adaptor());
484 : }
485 : frame = it->frame();
486 :
487 : // Get the number of arguments and construct an arguments object
488 : // mirror for the right frame and the underlying function.
489 61953 : const int length = frame->ComputeParametersCount();
490 61953 : Handle<JSFunction> function(frame->function(), isolate);
491 : Handle<JSObject> arguments =
492 61953 : isolate->factory()->NewArgumentsObject(function, length);
493 61953 : Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
494 :
495 : // Copy the parameters to the arguments object.
496 : DCHECK(array->length() == length);
497 334505 : for (int i = 0; i < length; i++) {
498 136276 : Object value = frame->GetParameter(i);
499 136276 : if (value->IsTheHole(isolate)) {
500 : // Generators currently use holes as dummy arguments when resuming. We
501 : // must not leak those.
502 : DCHECK(IsResumableFunction(function->shared()->kind()));
503 : value = ReadOnlyRoots(isolate).undefined_value();
504 : }
505 136276 : array->set(i, value);
506 : }
507 123906 : arguments->set_elements(*array);
508 :
509 : // Return the freshly allocated arguments object.
510 61953 : return arguments;
511 : }
512 :
513 : } // namespace
514 :
515 11028 : Handle<JSObject> Accessors::FunctionGetArguments(JavaScriptFrame* frame,
516 : int inlined_jsframe_index) {
517 : Isolate* isolate = frame->isolate();
518 : Address requested_frame_fp = frame->fp();
519 : // Forward a frame iterator to the requested frame. This is needed because we
520 : // potentially need for advance it to the arguments adaptor frame later.
521 110489 : for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) {
522 110489 : if (it.frame()->fp() != requested_frame_fp) continue;
523 11028 : return GetFrameArguments(isolate, &it, inlined_jsframe_index);
524 : }
525 0 : UNREACHABLE(); // Requested frame not found.
526 : return Handle<JSObject>();
527 : }
528 :
529 :
530 54714 : void Accessors::FunctionArgumentsGetter(
531 : v8::Local<v8::Name> name,
532 : const v8::PropertyCallbackInfo<v8::Value>& info) {
533 : i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
534 : HandleScope scope(isolate);
535 : Handle<JSFunction> function =
536 : Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
537 : Handle<Object> result = isolate->factory()->null_value();
538 54714 : if (!function->shared()->native()) {
539 : // Find the top invocation of the function by traversing frames.
540 106761 : for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) {
541 : JavaScriptFrame* frame = it.frame();
542 105666 : int function_index = FindFunctionInFrame(frame, function);
543 105666 : if (function_index >= 0) {
544 53619 : result = GetFrameArguments(isolate, &it, function_index);
545 53619 : break;
546 : }
547 : }
548 : }
549 : info.GetReturnValue().Set(Utils::ToLocal(result));
550 54714 : }
551 :
552 56 : Handle<AccessorInfo> Accessors::MakeFunctionArgumentsInfo(Isolate* isolate) {
553 : return MakeAccessor(isolate, isolate->factory()->arguments_string(),
554 56 : &FunctionArgumentsGetter, nullptr);
555 : }
556 :
557 :
558 : //
559 : // Accessors::FunctionCaller
560 : //
561 :
562 : static inline bool AllowAccessToFunction(Context current_context,
563 : JSFunction function) {
564 17476 : return current_context->HasSameSecurityTokenAs(function->context());
565 : }
566 :
567 7578 : class FrameFunctionIterator {
568 : public:
569 3789 : explicit FrameFunctionIterator(Isolate* isolate)
570 11367 : : isolate_(isolate), frame_iterator_(isolate), inlined_frame_index_(-1) {
571 : GetFrames();
572 3789 : }
573 :
574 : // Iterate through functions until the first occurrence of 'function'.
575 : // Returns true if one is found, and false if the iterator ends before.
576 3789 : bool Find(Handle<JSFunction> function) {
577 10564 : do {
578 23324 : if (!next().ToHandle(&function_)) return false;
579 : } while (!function_.is_identical_to(function));
580 : return true;
581 : }
582 :
583 : // Iterate through functions until the next non-toplevel one is found.
584 : // Returns true if one is found, and false if the iterator ends before.
585 2691 : bool FindNextNonTopLevel() {
586 4563 : do {
587 9288 : if (!next().ToHandle(&function_)) return false;
588 : } while (function_->shared()->is_toplevel());
589 : return true;
590 : }
591 :
592 : // Iterate through function until the first native or user-provided function
593 : // is found. Functions not defined in user-provided scripts are not visible
594 : // unless directly exposed, in which case the native flag is set on them.
595 : // Returns true if one is found, and false if the iterator ends before.
596 2610 : bool FindFirstNativeOrUserJavaScript() {
597 7731 : while (!function_->shared()->native() &&
598 5121 : !function_->shared()->IsUserJavaScript()) {
599 0 : if (!next().ToHandle(&function_)) return false;
600 : }
601 : return true;
602 : }
603 :
604 : // In case of inlined frames the function could have been materialized from
605 : // deoptimization information. If that is the case we need to make sure that
606 : // subsequent call will see the same function, since we are about to hand out
607 : // the value to JavaScript. Make sure to store the materialized value and
608 : // trigger a deoptimization of the underlying frame.
609 2610 : Handle<JSFunction> MaterializeFunction() {
610 2610 : if (inlined_frame_index_ == 0) return function_;
611 :
612 : JavaScriptFrame* frame = frame_iterator_.frame();
613 45 : TranslatedState translated_values(frame);
614 45 : translated_values.Prepare(frame->fp());
615 :
616 : TranslatedFrame* translated_frame =
617 45 : translated_values.GetFrameFromJSFrameIndex(inlined_frame_index_);
618 : TranslatedFrame::iterator iter = translated_frame->begin();
619 :
620 : // First value is the function.
621 45 : bool should_deoptimize = iter->IsMaterializedObject();
622 45 : Handle<Object> value = iter->GetValue();
623 45 : if (should_deoptimize) {
624 24 : translated_values.StoreMaterializedValuesAndDeopt(frame);
625 : }
626 :
627 : return Handle<JSFunction>::cast(value);
628 : }
629 :
630 : private:
631 16306 : MaybeHandle<JSFunction> next() {
632 : while (true) {
633 16333 : if (inlined_frame_index_ <= 0) {
634 12098 : if (!frame_iterator_.done()) {
635 12044 : frame_iterator_.Advance();
636 : frames_.clear();
637 12044 : inlined_frame_index_ = -1;
638 : GetFrames();
639 : }
640 12098 : if (inlined_frame_index_ == -1) return MaybeHandle<JSFunction>();
641 : }
642 :
643 15154 : --inlined_frame_index_;
644 : Handle<JSFunction> next_function =
645 15154 : frames_[inlined_frame_index_].AsJavaScript().function();
646 : // Skip functions from other origins.
647 30308 : if (!AllowAccessToFunction(isolate_->context(), *next_function)) continue;
648 15127 : return next_function;
649 : }
650 : }
651 : void GetFrames() {
652 : DCHECK_EQ(-1, inlined_frame_index_);
653 15833 : if (frame_iterator_.done()) return;
654 : JavaScriptFrame* frame = frame_iterator_.frame();
655 14654 : frame->Summarize(&frames_);
656 14654 : inlined_frame_index_ = static_cast<int>(frames_.size());
657 : DCHECK_LT(0, inlined_frame_index_);
658 : }
659 : Isolate* isolate_;
660 : Handle<JSFunction> function_;
661 : JavaScriptFrameIterator frame_iterator_;
662 : std::vector<FrameSummary> frames_;
663 : int inlined_frame_index_;
664 : };
665 :
666 :
667 3789 : MaybeHandle<JSFunction> FindCaller(Isolate* isolate,
668 : Handle<JSFunction> function) {
669 3789 : FrameFunctionIterator it(isolate);
670 3789 : if (function->shared()->native()) {
671 0 : return MaybeHandle<JSFunction>();
672 : }
673 : // Find the function from the frames. Return null in case no frame
674 : // corresponding to the given function was found.
675 3789 : if (!it.Find(function)) {
676 1098 : return MaybeHandle<JSFunction>();
677 : }
678 : // Find previously called non-toplevel function.
679 2691 : if (!it.FindNextNonTopLevel()) {
680 81 : return MaybeHandle<JSFunction>();
681 : }
682 : // Find the first user-land JavaScript function (or the entry point into
683 : // native JavaScript builtins in case such a builtin was the caller).
684 2610 : if (!it.FindFirstNativeOrUserJavaScript()) {
685 0 : return MaybeHandle<JSFunction>();
686 : }
687 :
688 : // Materialize the function that the iterator is currently sitting on. Note
689 : // that this might trigger deoptimization in case the function was actually
690 : // materialized. Identity of the function must be preserved because we are
691 : // going to return it to JavaScript after this point.
692 2610 : Handle<JSFunction> caller = it.MaterializeFunction();
693 :
694 : // Censor if the caller is not a sloppy mode function.
695 : // Change from ES5, which used to throw, see:
696 : // https://bugs.ecmascript.org/show_bug.cgi?id=310
697 2610 : if (is_strict(caller->shared()->language_mode())) {
698 288 : return MaybeHandle<JSFunction>();
699 : }
700 : // Don't return caller from another security context.
701 2322 : if (!AllowAccessToFunction(isolate->context(), *caller)) {
702 0 : return MaybeHandle<JSFunction>();
703 : }
704 2322 : return caller;
705 : }
706 :
707 :
708 3789 : void Accessors::FunctionCallerGetter(
709 : v8::Local<v8::Name> name,
710 : const v8::PropertyCallbackInfo<v8::Value>& info) {
711 : i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
712 : HandleScope scope(isolate);
713 : Handle<JSFunction> function =
714 3789 : Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
715 : Handle<Object> result;
716 : MaybeHandle<JSFunction> maybe_caller;
717 3789 : maybe_caller = FindCaller(isolate, function);
718 : Handle<JSFunction> caller;
719 3789 : if (maybe_caller.ToHandle(&caller)) {
720 : result = caller;
721 : } else {
722 : result = isolate->factory()->null_value();
723 : }
724 : info.GetReturnValue().Set(Utils::ToLocal(result));
725 3789 : }
726 :
727 56 : Handle<AccessorInfo> Accessors::MakeFunctionCallerInfo(Isolate* isolate) {
728 : return MakeAccessor(isolate, isolate->factory()->caller_string(),
729 56 : &FunctionCallerGetter, nullptr);
730 : }
731 :
732 :
733 : //
734 : // Accessors::BoundFunctionLength
735 : //
736 :
737 316 : void Accessors::BoundFunctionLengthGetter(
738 : v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
739 : i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
740 : RuntimeCallTimerScope timer(isolate,
741 316 : RuntimeCallCounterId::kBoundFunctionLengthGetter);
742 : HandleScope scope(isolate);
743 : Handle<JSBoundFunction> function =
744 316 : Handle<JSBoundFunction>::cast(Utils::OpenHandle(*info.Holder()));
745 :
746 : int length = 0;
747 632 : if (!JSBoundFunction::GetLength(isolate, function).To(&length)) {
748 0 : isolate->OptionalRescheduleException(false);
749 : return;
750 : }
751 : Handle<Object> result(Smi::FromInt(length), isolate);
752 : info.GetReturnValue().Set(Utils::ToLocal(result));
753 : }
754 :
755 56 : Handle<AccessorInfo> Accessors::MakeBoundFunctionLengthInfo(Isolate* isolate) {
756 : return MakeAccessor(isolate, isolate->factory()->length_string(),
757 56 : &BoundFunctionLengthGetter, &ReconfigureToDataProperty);
758 : }
759 :
760 : //
761 : // Accessors::BoundFunctionName
762 : //
763 :
764 82 : void Accessors::BoundFunctionNameGetter(
765 : v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
766 : i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
767 : RuntimeCallTimerScope timer(isolate,
768 82 : RuntimeCallCounterId::kBoundFunctionNameGetter);
769 : HandleScope scope(isolate);
770 : Handle<JSBoundFunction> function =
771 82 : Handle<JSBoundFunction>::cast(Utils::OpenHandle(*info.Holder()));
772 : Handle<Object> result;
773 164 : if (!JSBoundFunction::GetName(isolate, function).ToHandle(&result)) {
774 0 : isolate->OptionalRescheduleException(false);
775 : return;
776 : }
777 : info.GetReturnValue().Set(Utils::ToLocal(result));
778 : }
779 :
780 56 : Handle<AccessorInfo> Accessors::MakeBoundFunctionNameInfo(Isolate* isolate) {
781 : return MakeAccessor(isolate, isolate->factory()->name_string(),
782 56 : &BoundFunctionNameGetter, &ReconfigureToDataProperty);
783 : }
784 :
785 : //
786 : // Accessors::ErrorStack
787 : //
788 :
789 18721 : void Accessors::ErrorStackGetter(
790 : v8::Local<v8::Name> key, const v8::PropertyCallbackInfo<v8::Value>& info) {
791 : i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
792 : HandleScope scope(isolate);
793 : Handle<JSObject> holder =
794 : Handle<JSObject>::cast(Utils::OpenHandle(*info.Holder()));
795 :
796 : // Retrieve the stack trace. It can either be structured data in the form of
797 : // a FrameArray, an already formatted stack trace (string) or whatever the
798 : // "prepareStackTrace" callback produced.
799 :
800 : Handle<Object> stack_trace;
801 : Handle<Symbol> stack_trace_symbol = isolate->factory()->stack_trace_symbol();
802 : MaybeHandle<Object> maybe_stack_trace =
803 18721 : JSObject::GetProperty(isolate, holder, stack_trace_symbol);
804 37442 : if (!maybe_stack_trace.ToHandle(&stack_trace) ||
805 : stack_trace->IsUndefined(isolate)) {
806 : Handle<Object> result = isolate->factory()->undefined_value();
807 : info.GetReturnValue().Set(Utils::ToLocal(result));
808 : return;
809 : }
810 :
811 : // Only format the stack-trace the first time around. The check for a
812 : // FixedArray is sufficient as the user callback can not create plain
813 : // FixedArrays and the result is a String in case we format the stack
814 : // trace ourselves.
815 :
816 18703 : if (!stack_trace->IsFixedArray()) {
817 : info.GetReturnValue().Set(Utils::ToLocal(stack_trace));
818 : return;
819 : }
820 :
821 : Handle<Object> formatted_stack_trace;
822 30670 : if (!ErrorUtils::FormatStackTrace(isolate, holder, stack_trace)
823 : .ToHandle(&formatted_stack_trace)) {
824 116 : isolate->OptionalRescheduleException(false);
825 116 : return;
826 : }
827 :
828 : // Replace the structured stack-trace with the formatting result.
829 : MaybeHandle<Object> result = Object::SetProperty(
830 : isolate, holder, isolate->factory()->stack_trace_symbol(),
831 : formatted_stack_trace, StoreOrigin::kMaybeKeyed,
832 15219 : Just(ShouldThrow::kThrowOnError));
833 15219 : if (result.is_null()) {
834 0 : isolate->OptionalRescheduleException(false);
835 0 : return;
836 : }
837 :
838 : v8::Local<v8::Value> value = Utils::ToLocal(formatted_stack_trace);
839 : info.GetReturnValue().Set(value);
840 : }
841 :
842 167 : void Accessors::ErrorStackSetter(
843 : v8::Local<v8::Name> name, v8::Local<v8::Value> val,
844 : const v8::PropertyCallbackInfo<v8::Boolean>& info) {
845 : i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
846 : HandleScope scope(isolate);
847 : Handle<JSObject> obj = Handle<JSObject>::cast(
848 : Utils::OpenHandle(*v8::Local<v8::Value>(info.This())));
849 167 : Handle<Object> value = Handle<Object>::cast(Utils::OpenHandle(*val));
850 :
851 : // Store the value in the internal symbol to avoid reconfiguration to
852 : // a data property.
853 : MaybeHandle<Object> result = Object::SetProperty(
854 : isolate, obj, isolate->factory()->stack_trace_symbol(), value,
855 167 : StoreOrigin::kMaybeKeyed, Just(ShouldThrow::kThrowOnError));
856 167 : if (result.is_null()) {
857 0 : isolate->OptionalRescheduleException(false);
858 : return;
859 : }
860 : }
861 :
862 56 : Handle<AccessorInfo> Accessors::MakeErrorStackInfo(Isolate* isolate) {
863 : return MakeAccessor(isolate, isolate->factory()->stack_string(),
864 56 : &ErrorStackGetter, &ErrorStackSetter);
865 : }
866 :
867 : } // namespace internal
868 121996 : } // namespace v8
|