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