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
23namespace v8 {
24namespace internal {
25
26Handle<AccessorInfo> Accessors::MakeAccessor(
27 Isolate* isolate, Handle<Name> name, AccessorNameGetterCallback getter,
28 AccessorNameBooleanSetterCallback setter) {
29 Factory* factory = isolate->factory();
30 Handle<AccessorInfo> info = factory->NewAccessorInfo();
31 info->set_all_can_read(false);
32 info->set_all_can_write(false);
33 info->set_is_special_data_property(true);
34 info->set_is_sloppy(false);
35 info->set_replace_on_access(false);
36 info->set_getter_side_effect_type(SideEffectType::kHasSideEffect);
37 info->set_setter_side_effect_type(SideEffectType::kHasSideEffect);
38 name = factory->InternalizeName(name);
39 info->set_name(*name);
40 Handle<Object> get = v8::FromCData(isolate, getter);
41 if (setter == nullptr) setter = &ReconfigureToDataProperty;
42 Handle<Object> set = v8::FromCData(isolate, setter);
43 info->set_getter(*get);
44 info->set_setter(*set);
45 Address redirected = info->redirected_getter();
46 if (redirected != kNullAddress) {
47 Handle<Object> js_get = v8::FromCData(isolate, redirected);
48 info->set_js_getter(*js_get);
49 }
50 return info;
51}
52
53static V8_INLINE bool CheckForName(Isolate* isolate, Handle<Name> name,
54 Handle<String> property_name, int offset,
55 FieldIndex::Encoding encoding,
56 FieldIndex* index) {
57 if (Name::Equals(isolate, name, property_name)) {
58 *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.
67bool Accessors::IsJSObjectFieldAccessor(Isolate* isolate, Handle<Map> map,
68 Handle<Name> name, FieldIndex* index) {
69 switch (map->instance_type()) {
70 case JS_ARRAY_TYPE:
71 return CheckForName(isolate, name, isolate->factory()->length_string(),
72 JSArray::kLengthOffset, FieldIndex::kTagged, index);
73 default:
74 if (map->instance_type() < FIRST_NONSTRING_TYPE) {
75 return CheckForName(isolate, name, isolate->factory()->length_string(),
76 String::kLengthOffset, FieldIndex::kWord32, index);
77 }
78
79 return false;
80 }
81}
82
83V8_WARN_UNUSED_RESULT MaybeHandle<Object>
84Accessors::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 if (it.state() == LookupIterator::ACCESS_CHECK) {
93 CHECK(it.HasAccess());
94 it.Next();
95 }
96 DCHECK(holder.is_identical_to(it.GetHolder<JSObject>()));
97 CHECK_EQ(LookupIterator::ACCESSOR, it.state());
98 it.ReconfigureDataProperty(value, it.property_attributes());
99 return value;
100}
101
102
103//
104// Accessors::ReconfigureToDataProperty
105//
106void 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 isolate, RuntimeCallCounterId::kReconfigureToDataProperty);
112 HandleScope scope(isolate);
113 Handle<Object> receiver = Utils::OpenHandle(*info.This());
114 Handle<JSObject> holder =
115 Handle<JSObject>::cast(Utils::OpenHandle(*info.Holder()));
116 Handle<Name> name = Utils::OpenHandle(*key);
117 Handle<Object> value = Utils::OpenHandle(*val);
118 MaybeHandle<Object> result =
119 Accessors::ReplaceAccessorWithDataProperty(receiver, holder, name, value);
120 if (result.is_null()) {
121 isolate->OptionalRescheduleException(false);
122 } else {
123 info.GetReturnValue().Set(true);
124 }
125}
126
127
128//
129// Accessors::ArgumentsIterator
130//
131
132
133void 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 Object result = isolate->native_context()->array_values_iterator();
139 info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(result, isolate)));
140}
141
142Handle<AccessorInfo> Accessors::MakeArgumentsIteratorInfo(Isolate* isolate) {
143 Handle<Name> name = isolate->factory()->iterator_symbol();
144 return MakeAccessor(isolate, name, &ArgumentsIteratorGetter, nullptr);
145}
146
147
148//
149// Accessors::ArrayLength
150//
151
152
153void 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 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}
165
166void 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 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 Handle<Object> length_obj = Utils::OpenHandle(*val);
180
181 bool was_readonly = JSArray::HasReadOnlyLength(array);
182
183 uint32_t length = 0;
184 if (!JSArray::AnythingToArrayLength(isolate, length_obj, &length)) {
185 isolate->OptionalRescheduleException(false);
186 return;
187 }
188
189 if (!was_readonly && V8_UNLIKELY(JSArray::HasReadOnlyLength(array)) &&
190 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 if (info.ShouldThrowOnError()) {
196 Factory* factory = isolate->factory();
197 isolate->Throw(*factory->NewTypeError(
198 MessageTemplate::kStrictReadOnlyProperty, Utils::OpenHandle(*name),
199 i::Object::TypeOf(isolate, object), object));
200 isolate->OptionalRescheduleException(false);
201 } else {
202 info.GetReturnValue().Set(false);
203 }
204 return;
205 }
206
207 JSArray::SetLength(array, length);
208
209 uint32_t actual_new_len = 0;
210 CHECK(array->length()->ToArrayLength(&actual_new_len));
211 // Fail if there were non-deletable elements.
212 if (actual_new_len != length) {
213 if (info.ShouldThrowOnError()) {
214 Factory* factory = isolate->factory();
215 isolate->Throw(*factory->NewTypeError(
216 MessageTemplate::kStrictDeleteProperty,
217 factory->NewNumberFromUint(actual_new_len - 1), array));
218 isolate->OptionalRescheduleException(false);
219 } else {
220 info.GetReturnValue().Set(false);
221 }
222 } else {
223 info.GetReturnValue().Set(true);
224 }
225}
226
227Handle<AccessorInfo> Accessors::MakeArrayLengthInfo(Isolate* isolate) {
228 return MakeAccessor(isolate, isolate->factory()->length_string(),
229 &ArrayLengthGetter, &ArrayLengthSetter);
230}
231
232//
233// Accessors::ModuleNamespaceEntry
234//
235
236void 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 JSModuleNamespace::cast(*Utils::OpenHandle(*info.Holder()));
242 Handle<Object> result;
243 if (!holder
244 ->GetExport(isolate, Handle<String>::cast(Utils::OpenHandle(*name)))
245 .ToHandle(&result)) {
246 isolate->OptionalRescheduleException(false);
247 } else {
248 info.GetReturnValue().Set(Utils::ToLocal(result));
249 }
250}
251
252void 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 if (info.ShouldThrowOnError()) {
262 isolate->Throw(*factory->NewTypeError(
263 MessageTemplate::kStrictReadOnlyProperty, Utils::OpenHandle(*name),
264 i::Object::TypeOf(isolate, holder), holder));
265 isolate->OptionalRescheduleException(false);
266 } else {
267 info.GetReturnValue().Set(false);
268 }
269}
270
271Handle<AccessorInfo> Accessors::MakeModuleNamespaceEntryInfo(
272 Isolate* isolate, Handle<String> name) {
273 return MakeAccessor(isolate, name, &ModuleNamespaceEntryGetter,
274 &ModuleNamespaceEntrySetter);
275}
276
277
278//
279// Accessors::StringLength
280//
281
282void 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 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 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}
305
306Handle<AccessorInfo> Accessors::MakeStringLengthInfo(Isolate* isolate) {
307 return MakeAccessor(isolate, isolate->factory()->length_string(),
308 &StringLengthGetter, nullptr);
309}
310
311//
312// Accessors::FunctionPrototype
313//
314
315static Handle<Object> GetFunctionPrototype(Isolate* isolate,
316 Handle<JSFunction> function) {
317 if (!function->has_prototype()) {
318 Handle<Object> proto = isolate->factory()->NewFunctionPrototype(function);
319 JSFunction::SetPrototype(function, proto);
320 }
321 return Handle<Object>(function->prototype(), isolate);
322}
323
324void 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 RuntimeCallCounterId::kFunctionPrototypeGetter);
330 HandleScope scope(isolate);
331 Handle<JSFunction> function =
332 Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
333 DCHECK(function->has_prototype_property());
334 Handle<Object> result = GetFunctionPrototype(isolate, function);
335 info.GetReturnValue().Set(Utils::ToLocal(result));
336}
337
338void 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 RuntimeCallCounterId::kFunctionPrototypeSetter);
344 HandleScope scope(isolate);
345 Handle<Object> value = Utils::OpenHandle(*val);
346 Handle<JSFunction> object =
347 Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
348 DCHECK(object->has_prototype_property());
349 JSFunction::SetPrototype(object, value);
350 info.GetReturnValue().Set(true);
351}
352
353Handle<AccessorInfo> Accessors::MakeFunctionPrototypeInfo(Isolate* isolate) {
354 return MakeAccessor(isolate, isolate->factory()->prototype_string(),
355 &FunctionPrototypeGetter, &FunctionPrototypeSetter);
356}
357
358
359//
360// Accessors::FunctionLength
361//
362
363
364void 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 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}
377
378Handle<AccessorInfo> Accessors::MakeFunctionLengthInfo(Isolate* isolate) {
379 return MakeAccessor(isolate, isolate->factory()->length_string(),
380 &FunctionLengthGetter, &ReconfigureToDataProperty);
381}
382
383
384//
385// Accessors::FunctionName
386//
387
388
389void 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 Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
396 Handle<Object> result = JSFunction::GetName(isolate, function);
397 info.GetReturnValue().Set(Utils::ToLocal(result));
398}
399
400Handle<AccessorInfo> Accessors::MakeFunctionNameInfo(Isolate* isolate) {
401 return MakeAccessor(isolate, isolate->factory()->name_string(),
402 &FunctionNameGetter, &ReconfigureToDataProperty);
403}
404
405
406//
407// Accessors::FunctionArguments
408//
409
410namespace {
411
412Handle<JSObject> ArgumentsForInlinedFunction(JavaScriptFrame* frame,
413 int inlined_frame_index) {
414 Isolate* isolate = frame->isolate();
415 Factory* factory = isolate->factory();
416
417 TranslatedState translated_values(frame);
418 translated_values.Prepare(frame->fp());
419
420 int argument_count = 0;
421 TranslatedFrame* translated_frame =
422 translated_values.GetArgumentsInfoFromJSFrameIndex(inlined_frame_index,
423 &argument_count);
424 TranslatedFrame::iterator iter = translated_frame->begin();
425
426 // Materialize the function.
427 bool should_deoptimize = iter->IsMaterializedObject();
428 Handle<JSFunction> function = Handle<JSFunction>::cast(iter->GetValue());
429 iter++;
430
431 // Skip the receiver.
432 iter++;
433 argument_count--;
434
435 Handle<JSObject> arguments =
436 factory->NewArgumentsObject(function, argument_count);
437 Handle<FixedArray> array = factory->NewFixedArray(argument_count);
438 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 should_deoptimize = should_deoptimize || iter->IsMaterializedObject();
442 Handle<Object> value = iter->GetValue();
443 array->set(i, *value);
444 iter++;
445 }
446 arguments->set_elements(*array);
447
448 if (should_deoptimize) {
449 translated_values.StoreMaterializedValuesAndDeopt(frame);
450 }
451
452 // Return the freshly allocated arguments object.
453 return arguments;
454}
455
456int FindFunctionInFrame(JavaScriptFrame* frame, Handle<JSFunction> function) {
457 std::vector<FrameSummary> frames;
458 frame->Summarize(&frames);
459 for (size_t i = frames.size(); i != 0; i--) {
460 if (*frames[i - 1].AsJavaScript().function() == *function) {
461 return static_cast<int>(i) - 1;
462 }
463 }
464 return -1;
465}
466
467Handle<JSObject> GetFrameArguments(Isolate* isolate,
468 JavaScriptFrameIterator* it,
469 int function_index) {
470 JavaScriptFrame* frame = it->frame();
471
472 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 return ArgumentsForInlinedFunction(frame, function_index);
478 }
479
480 // Find the frame that holds the actual arguments passed to the function.
481 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 const int length = frame->ComputeParametersCount();
490 Handle<JSFunction> function(frame->function(), isolate);
491 Handle<JSObject> arguments =
492 isolate->factory()->NewArgumentsObject(function, length);
493 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
494
495 // Copy the parameters to the arguments object.
496 DCHECK(array->length() == length);
497 for (int i = 0; i < length; i++) {
498 Object value = frame->GetParameter(i);
499 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 array->set(i, value);
506 }
507 arguments->set_elements(*array);
508
509 // Return the freshly allocated arguments object.
510 return arguments;
511}
512
513} // namespace
514
515Handle<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 for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) {
522 if (it.frame()->fp() != requested_frame_fp) continue;
523 return GetFrameArguments(isolate, &it, inlined_jsframe_index);
524 }
525 UNREACHABLE(); // Requested frame not found.
526 return Handle<JSObject>();
527}
528
529
530void 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 if (!function->shared()->native()) {
539 // Find the top invocation of the function by traversing frames.
540 for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) {
541 JavaScriptFrame* frame = it.frame();
542 int function_index = FindFunctionInFrame(frame, function);
543 if (function_index >= 0) {
544 result = GetFrameArguments(isolate, &it, function_index);
545 break;
546 }
547 }
548 }
549 info.GetReturnValue().Set(Utils::ToLocal(result));
550}
551
552Handle<AccessorInfo> Accessors::MakeFunctionArgumentsInfo(Isolate* isolate) {
553 return MakeAccessor(isolate, isolate->factory()->arguments_string(),
554 &FunctionArgumentsGetter, nullptr);
555}
556
557
558//
559// Accessors::FunctionCaller
560//
561
562static inline bool AllowAccessToFunction(Context current_context,
563 JSFunction function) {
564 return current_context->HasSameSecurityTokenAs(function->context());
565}
566
567class FrameFunctionIterator {
568 public:
569 explicit FrameFunctionIterator(Isolate* isolate)
570 : isolate_(isolate), frame_iterator_(isolate), inlined_frame_index_(-1) {
571 GetFrames();
572 }
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 bool Find(Handle<JSFunction> function) {
577 do {
578 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 bool FindNextNonTopLevel() {
586 do {
587 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 bool FindFirstNativeOrUserJavaScript() {
597 while (!function_->shared()->native() &&
598 !function_->shared()->IsUserJavaScript()) {
599 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 Handle<JSFunction> MaterializeFunction() {
610 if (inlined_frame_index_ == 0) return function_;
611
612 JavaScriptFrame* frame = frame_iterator_.frame();
613 TranslatedState translated_values(frame);
614 translated_values.Prepare(frame->fp());
615
616 TranslatedFrame* translated_frame =
617 translated_values.GetFrameFromJSFrameIndex(inlined_frame_index_);
618 TranslatedFrame::iterator iter = translated_frame->begin();
619
620 // First value is the function.
621 bool should_deoptimize = iter->IsMaterializedObject();
622 Handle<Object> value = iter->GetValue();
623 if (should_deoptimize) {
624 translated_values.StoreMaterializedValuesAndDeopt(frame);
625 }
626
627 return Handle<JSFunction>::cast(value);
628 }
629
630 private:
631 MaybeHandle<JSFunction> next() {
632 while (true) {
633 if (inlined_frame_index_ <= 0) {
634 if (!frame_iterator_.done()) {
635 frame_iterator_.Advance();
636 frames_.clear();
637 inlined_frame_index_ = -1;
638 GetFrames();
639 }
640 if (inlined_frame_index_ == -1) return MaybeHandle<JSFunction>();
641 }
642
643 --inlined_frame_index_;
644 Handle<JSFunction> next_function =
645 frames_[inlined_frame_index_].AsJavaScript().function();
646 // Skip functions from other origins.
647 if (!AllowAccessToFunction(isolate_->context(), *next_function)) continue;
648 return next_function;
649 }
650 }
651 void GetFrames() {
652 DCHECK_EQ(-1, inlined_frame_index_);
653 if (frame_iterator_.done()) return;
654 JavaScriptFrame* frame = frame_iterator_.frame();
655 frame->Summarize(&frames_);
656 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
667MaybeHandle<JSFunction> FindCaller(Isolate* isolate,
668 Handle<JSFunction> function) {
669 FrameFunctionIterator it(isolate);
670 if (function->shared()->native()) {
671 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 if (!it.Find(function)) {
676 return MaybeHandle<JSFunction>();
677 }
678 // Find previously called non-toplevel function.
679 if (!it.FindNextNonTopLevel()) {
680 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 if (!it.FindFirstNativeOrUserJavaScript()) {
685 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 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 if (is_strict(caller->shared()->language_mode())) {
698 return MaybeHandle<JSFunction>();
699 }
700 // Don't return caller from another security context.
701 if (!AllowAccessToFunction(isolate->context(), *caller)) {
702 return MaybeHandle<JSFunction>();
703 }
704 return caller;
705}
706
707
708void 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 Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
715 Handle<Object> result;
716 MaybeHandle<JSFunction> maybe_caller;
717 maybe_caller = FindCaller(isolate, function);
718 Handle<JSFunction> caller;
719 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}
726
727Handle<AccessorInfo> Accessors::MakeFunctionCallerInfo(Isolate* isolate) {
728 return MakeAccessor(isolate, isolate->factory()->caller_string(),
729 &FunctionCallerGetter, nullptr);
730}
731
732
733//
734// Accessors::BoundFunctionLength
735//
736
737void 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 RuntimeCallCounterId::kBoundFunctionLengthGetter);
742 HandleScope scope(isolate);
743 Handle<JSBoundFunction> function =
744 Handle<JSBoundFunction>::cast(Utils::OpenHandle(*info.Holder()));
745
746 int length = 0;
747 if (!JSBoundFunction::GetLength(isolate, function).To(&length)) {
748 isolate->OptionalRescheduleException(false);
749 return;
750 }
751 Handle<Object> result(Smi::FromInt(length), isolate);
752 info.GetReturnValue().Set(Utils::ToLocal(result));
753}
754
755Handle<AccessorInfo> Accessors::MakeBoundFunctionLengthInfo(Isolate* isolate) {
756 return MakeAccessor(isolate, isolate->factory()->length_string(),
757 &BoundFunctionLengthGetter, &ReconfigureToDataProperty);
758}
759
760//
761// Accessors::BoundFunctionName
762//
763
764void 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 RuntimeCallCounterId::kBoundFunctionNameGetter);
769 HandleScope scope(isolate);
770 Handle<JSBoundFunction> function =
771 Handle<JSBoundFunction>::cast(Utils::OpenHandle(*info.Holder()));
772 Handle<Object> result;
773 if (!JSBoundFunction::GetName(isolate, function).ToHandle(&result)) {
774 isolate->OptionalRescheduleException(false);
775 return;
776 }
777 info.GetReturnValue().Set(Utils::ToLocal(result));
778}
779
780Handle<AccessorInfo> Accessors::MakeBoundFunctionNameInfo(Isolate* isolate) {
781 return MakeAccessor(isolate, isolate->factory()->name_string(),
782 &BoundFunctionNameGetter, &ReconfigureToDataProperty);
783}
784
785//
786// Accessors::ErrorStack
787//
788
789namespace {
790
791MaybeHandle<JSReceiver> ClearInternalStackTrace(Isolate* isolate,
792 Handle<JSObject> error) {
793 RETURN_ON_EXCEPTION(
794 isolate,
795 Object::SetProperty(
796 isolate, error, isolate->factory()->stack_trace_symbol(),
797 isolate->factory()->undefined_value(), StoreOrigin::kMaybeKeyed,
798 Just(ShouldThrow::kThrowOnError)),
799 JSReceiver);
800 return error;
801}
802
803bool IsAccessor(Handle<Object> receiver, Handle<Name> name,
804 Handle<JSObject> holder) {
805 LookupIterator it(receiver, name, holder,
806 LookupIterator::OWN_SKIP_INTERCEPTOR);
807 // Skip any access checks we might hit. This accessor should never hit in a
808 // situation where the caller does not have access.
809 if (it.state() == LookupIterator::ACCESS_CHECK) {
810 CHECK(it.HasAccess());
811 it.Next();
812 }
813 return (it.state() == LookupIterator::ACCESSOR);
814}
815
816} // namespace
817
818void Accessors::ErrorStackGetter(
819 v8::Local<v8::Name> key, const v8::PropertyCallbackInfo<v8::Value>& info) {
820 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
821 HandleScope scope(isolate);
822 Handle<JSObject> holder =
823 Handle<JSObject>::cast(Utils::OpenHandle(*info.Holder()));
824
825 // Retrieve the structured stack trace.
826
827 Handle<Object> stack_trace;
828 Handle<Symbol> stack_trace_symbol = isolate->factory()->stack_trace_symbol();
829 MaybeHandle<Object> maybe_stack_trace =
830 JSObject::GetProperty(isolate, holder, stack_trace_symbol);
831 if (!maybe_stack_trace.ToHandle(&stack_trace) ||
832 stack_trace->IsUndefined(isolate)) {
833 Handle<Object> result = isolate->factory()->undefined_value();
834 info.GetReturnValue().Set(Utils::ToLocal(result));
835 return;
836 }
837
838 // Format it, clear the internal structured trace and reconfigure as a data
839 // property.
840
841 Handle<Object> formatted_stack_trace;
842 if (!ErrorUtils::FormatStackTrace(isolate, holder, stack_trace)
843 .ToHandle(&formatted_stack_trace)) {
844 isolate->OptionalRescheduleException(false);
845 return;
846 }
847
848 MaybeHandle<Object> result = ClearInternalStackTrace(isolate, holder);
849 if (result.is_null()) {
850 isolate->OptionalRescheduleException(false);
851 return;
852 }
853
854 // If stack is still an accessor (this could have changed in the meantime
855 // since FormatStackTrace can execute arbitrary JS), replace it with a data
856 // property.
857 Handle<Object> receiver =
858 Utils::OpenHandle(*v8::Local<v8::Value>(info.This()));
859 Handle<Name> name = Utils::OpenHandle(*key);
860 if (IsAccessor(receiver, name, holder)) {
861 result = Accessors::ReplaceAccessorWithDataProperty(receiver, holder, name,
862 formatted_stack_trace);
863 if (result.is_null()) {
864 isolate->OptionalRescheduleException(false);
865 return;
866 }
867 } else {
868 // The stack property has been modified in the meantime.
869 if (!JSObject::GetProperty(isolate, holder, name)
870 .ToHandle(&formatted_stack_trace)) {
871 isolate->OptionalRescheduleException(false);
872 return;
873 }
874 }
875
876 v8::Local<v8::Value> value = Utils::ToLocal(formatted_stack_trace);
877 info.GetReturnValue().Set(value);
878}
879
880void Accessors::ErrorStackSetter(
881 v8::Local<v8::Name> name, v8::Local<v8::Value> val,
882 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
883 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
884 HandleScope scope(isolate);
885 Handle<JSObject> obj = Handle<JSObject>::cast(
886 Utils::OpenHandle(*v8::Local<v8::Value>(info.This())));
887
888 // Clear internal properties to avoid memory leaks.
889 Handle<Symbol> stack_trace_symbol = isolate->factory()->stack_trace_symbol();
890 if (JSReceiver::HasOwnProperty(obj, stack_trace_symbol).FromMaybe(false)) {
891 ClearInternalStackTrace(isolate, obj);
892 }
893
894 Accessors::ReconfigureToDataProperty(name, val, info);
895}
896
897Handle<AccessorInfo> Accessors::MakeErrorStackInfo(Isolate* isolate) {
898 return MakeAccessor(isolate, isolate->factory()->stack_string(),
899 &ErrorStackGetter, &ErrorStackSetter);
900}
901
902} // namespace internal
903} // namespace v8
904