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.h"
8 #include "src/contexts.h"
9 #include "src/deoptimizer.h"
10 #include "src/execution.h"
11 #include "src/frames-inl.h"
12 #include "src/heap/factory.h"
13 #include "src/isolate-inl.h"
14 #include "src/messages.h"
15 #include "src/objects/api-callbacks.h"
16 #include "src/property-details.h"
17 #include "src/prototype.h"
18
19 namespace v8 {
20 namespace internal {
21
MakeAccessor(Isolate * isolate,Handle<Name> name,AccessorNameGetterCallback getter,AccessorNameBooleanSetterCallback setter)22 Handle<AccessorInfo> Accessors::MakeAccessor(
23 Isolate* isolate, Handle<Name> name, AccessorNameGetterCallback getter,
24 AccessorNameBooleanSetterCallback setter) {
25 Factory* factory = isolate->factory();
26 Handle<AccessorInfo> info = factory->NewAccessorInfo();
27 info->set_all_can_read(false);
28 info->set_all_can_write(false);
29 info->set_is_special_data_property(true);
30 info->set_is_sloppy(false);
31 info->set_replace_on_access(false);
32 info->set_has_no_side_effect(false);
33 name = factory->InternalizeName(name);
34 info->set_name(*name);
35 Handle<Object> get = v8::FromCData(isolate, getter);
36 if (setter == nullptr) setter = &ReconfigureToDataProperty;
37 Handle<Object> set = v8::FromCData(isolate, setter);
38 info->set_getter(*get);
39 info->set_setter(*set);
40 Address redirected = info->redirected_getter();
41 if (redirected != kNullAddress) {
42 Handle<Object> js_get = v8::FromCData(isolate, redirected);
43 info->set_js_getter(*js_get);
44 }
45 return info;
46 }
47
CheckForName(Handle<Name> name,Handle<String> property_name,int offset,FieldIndex::Encoding encoding,FieldIndex * index)48 static V8_INLINE bool CheckForName(Handle<Name> name,
49 Handle<String> property_name, int offset,
50 FieldIndex::Encoding encoding,
51 FieldIndex* index) {
52 if (Name::Equals(name, property_name)) {
53 *index = FieldIndex::ForInObjectOffset(offset, encoding);
54 return true;
55 }
56 return false;
57 }
58
59
60 // Returns true for properties that are accessors to object fields.
61 // If true, *object_offset contains offset of object field.
IsJSObjectFieldAccessor(Handle<Map> map,Handle<Name> name,FieldIndex * index)62 bool Accessors::IsJSObjectFieldAccessor(Handle<Map> map, Handle<Name> name,
63 FieldIndex* index) {
64 Isolate* isolate = name->GetIsolate();
65
66 switch (map->instance_type()) {
67 case JS_ARRAY_TYPE:
68 return CheckForName(name, isolate->factory()->length_string(),
69 JSArray::kLengthOffset, FieldIndex::kTagged, index);
70 default:
71 if (map->instance_type() < FIRST_NONSTRING_TYPE) {
72 return CheckForName(name, isolate->factory()->length_string(),
73 String::kLengthOffset, FieldIndex::kTagged, index);
74 }
75
76 return false;
77 }
78 }
79
80 V8_WARN_UNUSED_RESULT MaybeHandle<Object>
ReplaceAccessorWithDataProperty(Isolate * isolate,Handle<Object> receiver,Handle<JSObject> holder,Handle<Name> name,Handle<Object> value)81 Accessors::ReplaceAccessorWithDataProperty(Isolate* isolate,
82 Handle<Object> receiver,
83 Handle<JSObject> holder,
84 Handle<Name> name,
85 Handle<Object> value) {
86 LookupIterator it(receiver, name, holder,
87 LookupIterator::OWN_SKIP_INTERCEPTOR);
88 // Skip any access checks we might hit. This accessor should never hit in a
89 // situation where the caller does not have access.
90 if (it.state() == LookupIterator::ACCESS_CHECK) {
91 CHECK(it.HasAccess());
92 it.Next();
93 }
94 DCHECK(holder.is_identical_to(it.GetHolder<JSObject>()));
95 CHECK_EQ(LookupIterator::ACCESSOR, it.state());
96 it.ReconfigureDataProperty(value, it.property_attributes());
97 return value;
98 }
99
100
101 //
102 // Accessors::ReconfigureToDataProperty
103 //
ReconfigureToDataProperty(v8::Local<v8::Name> key,v8::Local<v8::Value> val,const v8::PropertyCallbackInfo<v8::Boolean> & info)104 void Accessors::ReconfigureToDataProperty(
105 v8::Local<v8::Name> key, v8::Local<v8::Value> val,
106 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
107 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
108 RuntimeCallTimerScope stats_scope(
109 isolate, RuntimeCallCounterId::kReconfigureToDataProperty);
110 HandleScope scope(isolate);
111 Handle<Object> receiver = Utils::OpenHandle(*info.This());
112 Handle<JSObject> holder =
113 Handle<JSObject>::cast(Utils::OpenHandle(*info.Holder()));
114 Handle<Name> name = Utils::OpenHandle(*key);
115 Handle<Object> value = Utils::OpenHandle(*val);
116 MaybeHandle<Object> result = Accessors::ReplaceAccessorWithDataProperty(
117 isolate, receiver, holder, name, value);
118 if (result.is_null()) {
119 isolate->OptionalRescheduleException(false);
120 } else {
121 info.GetReturnValue().Set(true);
122 }
123 }
124
125
126 //
127 // Accessors::ArgumentsIterator
128 //
129
130
ArgumentsIteratorGetter(v8::Local<v8::Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)131 void Accessors::ArgumentsIteratorGetter(
132 v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
133 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
134 DisallowHeapAllocation no_allocation;
135 HandleScope scope(isolate);
136 Object* result = isolate->native_context()->array_values_iterator();
137 info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(result, isolate)));
138 }
139
MakeArgumentsIteratorInfo(Isolate * isolate)140 Handle<AccessorInfo> Accessors::MakeArgumentsIteratorInfo(Isolate* isolate) {
141 Handle<Name> name = isolate->factory()->iterator_symbol();
142 return MakeAccessor(isolate, name, &ArgumentsIteratorGetter, nullptr);
143 }
144
145
146 //
147 // Accessors::ArrayLength
148 //
149
150
ArrayLengthGetter(v8::Local<v8::Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)151 void Accessors::ArrayLengthGetter(
152 v8::Local<v8::Name> name,
153 const v8::PropertyCallbackInfo<v8::Value>& info) {
154 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
155 RuntimeCallTimerScope timer(isolate,
156 RuntimeCallCounterId::kArrayLengthGetter);
157 DisallowHeapAllocation no_allocation;
158 HandleScope scope(isolate);
159 JSArray* holder = JSArray::cast(*Utils::OpenHandle(*info.Holder()));
160 Object* result = holder->length();
161 info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(result, isolate)));
162 }
163
ArrayLengthSetter(v8::Local<v8::Name> name,v8::Local<v8::Value> val,const v8::PropertyCallbackInfo<v8::Boolean> & info)164 void Accessors::ArrayLengthSetter(
165 v8::Local<v8::Name> name, v8::Local<v8::Value> val,
166 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
167 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
168 RuntimeCallTimerScope timer(isolate,
169 RuntimeCallCounterId::kArrayLengthSetter);
170 HandleScope scope(isolate);
171
172 DCHECK(Utils::OpenHandle(*name)->SameValue(isolate->heap()->length_string()));
173
174 Handle<JSReceiver> object = Utils::OpenHandle(*info.Holder());
175 Handle<JSArray> array = Handle<JSArray>::cast(object);
176 Handle<Object> length_obj = Utils::OpenHandle(*val);
177
178 bool was_readonly = JSArray::HasReadOnlyLength(array);
179
180 uint32_t length = 0;
181 if (!JSArray::AnythingToArrayLength(isolate, length_obj, &length)) {
182 isolate->OptionalRescheduleException(false);
183 return;
184 }
185
186 if (!was_readonly && V8_UNLIKELY(JSArray::HasReadOnlyLength(array)) &&
187 length != array->length()->Number()) {
188 // AnythingToArrayLength() may have called setter re-entrantly and modified
189 // its property descriptor. Don't perform this check if "length" was
190 // previously readonly, as this may have been called during
191 // DefineOwnPropertyIgnoreAttributes().
192 if (info.ShouldThrowOnError()) {
193 Factory* factory = isolate->factory();
194 isolate->Throw(*factory->NewTypeError(
195 MessageTemplate::kStrictReadOnlyProperty, Utils::OpenHandle(*name),
196 i::Object::TypeOf(isolate, object), object));
197 isolate->OptionalRescheduleException(false);
198 } else {
199 info.GetReturnValue().Set(false);
200 }
201 return;
202 }
203
204 JSArray::SetLength(array, length);
205
206 uint32_t actual_new_len = 0;
207 CHECK(array->length()->ToArrayLength(&actual_new_len));
208 // Fail if there were non-deletable elements.
209 if (actual_new_len != length) {
210 if (info.ShouldThrowOnError()) {
211 Factory* factory = isolate->factory();
212 isolate->Throw(*factory->NewTypeError(
213 MessageTemplate::kStrictDeleteProperty,
214 factory->NewNumberFromUint(actual_new_len - 1), array));
215 isolate->OptionalRescheduleException(false);
216 } else {
217 info.GetReturnValue().Set(false);
218 }
219 } else {
220 info.GetReturnValue().Set(true);
221 }
222 }
223
MakeArrayLengthInfo(Isolate * isolate)224 Handle<AccessorInfo> Accessors::MakeArrayLengthInfo(Isolate* isolate) {
225 return MakeAccessor(isolate, isolate->factory()->length_string(),
226 &ArrayLengthGetter, &ArrayLengthSetter);
227 }
228
229 //
230 // Accessors::ModuleNamespaceEntry
231 //
232
ModuleNamespaceEntryGetter(v8::Local<v8::Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)233 void Accessors::ModuleNamespaceEntryGetter(
234 v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
235 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
236 HandleScope scope(isolate);
237 JSModuleNamespace* holder =
238 JSModuleNamespace::cast(*Utils::OpenHandle(*info.Holder()));
239 Handle<Object> result;
240 if (!holder->GetExport(Handle<String>::cast(Utils::OpenHandle(*name)))
241 .ToHandle(&result)) {
242 isolate->OptionalRescheduleException(false);
243 } else {
244 info.GetReturnValue().Set(Utils::ToLocal(result));
245 }
246 }
247
ModuleNamespaceEntrySetter(v8::Local<v8::Name> name,v8::Local<v8::Value> val,const v8::PropertyCallbackInfo<v8::Boolean> & info)248 void Accessors::ModuleNamespaceEntrySetter(
249 v8::Local<v8::Name> name, v8::Local<v8::Value> val,
250 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
251 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
252 HandleScope scope(isolate);
253 Factory* factory = isolate->factory();
254 Handle<JSModuleNamespace> holder =
255 Handle<JSModuleNamespace>::cast(Utils::OpenHandle(*info.Holder()));
256
257 if (info.ShouldThrowOnError()) {
258 isolate->Throw(*factory->NewTypeError(
259 MessageTemplate::kStrictReadOnlyProperty, Utils::OpenHandle(*name),
260 i::Object::TypeOf(isolate, holder), holder));
261 isolate->OptionalRescheduleException(false);
262 } else {
263 info.GetReturnValue().Set(false);
264 }
265 }
266
MakeModuleNamespaceEntryInfo(Isolate * isolate,Handle<String> name)267 Handle<AccessorInfo> Accessors::MakeModuleNamespaceEntryInfo(
268 Isolate* isolate, Handle<String> name) {
269 return MakeAccessor(isolate, name, &ModuleNamespaceEntryGetter,
270 &ModuleNamespaceEntrySetter);
271 }
272
273
274 //
275 // Accessors::StringLength
276 //
277
StringLengthGetter(v8::Local<v8::Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)278 void Accessors::StringLengthGetter(
279 v8::Local<v8::Name> name,
280 const v8::PropertyCallbackInfo<v8::Value>& info) {
281 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
282 RuntimeCallTimerScope timer(isolate,
283 RuntimeCallCounterId::kStringLengthGetter);
284 DisallowHeapAllocation no_allocation;
285 HandleScope scope(isolate);
286
287 // We have a slight impedance mismatch between the external API and the way we
288 // use callbacks internally: Externally, callbacks can only be used with
289 // v8::Object, but internally we have callbacks on entities which are higher
290 // in the hierarchy, in this case for String values.
291
292 Object* value = *Utils::OpenHandle(*v8::Local<v8::Value>(info.This()));
293 if (!value->IsString()) {
294 // Not a string value. That means that we either got a String wrapper or
295 // a Value with a String wrapper in its prototype chain.
296 value = JSValue::cast(*Utils::OpenHandle(*info.Holder()))->value();
297 }
298 Object* result = Smi::FromInt(String::cast(value)->length());
299 info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(result, isolate)));
300 }
301
MakeStringLengthInfo(Isolate * isolate)302 Handle<AccessorInfo> Accessors::MakeStringLengthInfo(Isolate* isolate) {
303 return MakeAccessor(isolate, isolate->factory()->length_string(),
304 &StringLengthGetter, nullptr);
305 }
306
307 //
308 // Accessors::ScriptColumnOffset
309 //
310
311
ScriptColumnOffsetGetter(v8::Local<v8::Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)312 void Accessors::ScriptColumnOffsetGetter(
313 v8::Local<v8::Name> name,
314 const v8::PropertyCallbackInfo<v8::Value>& info) {
315 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
316 DisallowHeapAllocation no_allocation;
317 HandleScope scope(isolate);
318 Object* object = *Utils::OpenHandle(*info.Holder());
319 Object* res = Smi::FromInt(
320 Script::cast(JSValue::cast(object)->value())->column_offset());
321 info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(res, isolate)));
322 }
323
MakeScriptColumnOffsetInfo(Isolate * isolate)324 Handle<AccessorInfo> Accessors::MakeScriptColumnOffsetInfo(Isolate* isolate) {
325 Handle<String> name(isolate->factory()->InternalizeOneByteString(
326 STATIC_CHAR_VECTOR("column_offset")));
327 return MakeAccessor(isolate, name, &ScriptColumnOffsetGetter, nullptr);
328 }
329
330
331 //
332 // Accessors::ScriptId
333 //
334
335
ScriptIdGetter(v8::Local<v8::Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)336 void Accessors::ScriptIdGetter(
337 v8::Local<v8::Name> name,
338 const v8::PropertyCallbackInfo<v8::Value>& info) {
339 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
340 DisallowHeapAllocation no_allocation;
341 HandleScope scope(isolate);
342 Object* object = *Utils::OpenHandle(*info.Holder());
343 Object* id = Smi::FromInt(Script::cast(JSValue::cast(object)->value())->id());
344 info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(id, isolate)));
345 }
346
MakeScriptIdInfo(Isolate * isolate)347 Handle<AccessorInfo> Accessors::MakeScriptIdInfo(Isolate* isolate) {
348 Handle<String> name(
349 isolate->factory()->InternalizeOneByteString(STATIC_CHAR_VECTOR("id")));
350 return MakeAccessor(isolate, name, &ScriptIdGetter, nullptr);
351 }
352
353
354 //
355 // Accessors::ScriptName
356 //
357
358
ScriptNameGetter(v8::Local<v8::Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)359 void Accessors::ScriptNameGetter(
360 v8::Local<v8::Name> name,
361 const v8::PropertyCallbackInfo<v8::Value>& info) {
362 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
363 DisallowHeapAllocation no_allocation;
364 HandleScope scope(isolate);
365 Object* object = *Utils::OpenHandle(*info.Holder());
366 Object* source = Script::cast(JSValue::cast(object)->value())->name();
367 info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(source, isolate)));
368 }
369
MakeScriptNameInfo(Isolate * isolate)370 Handle<AccessorInfo> Accessors::MakeScriptNameInfo(Isolate* isolate) {
371 return MakeAccessor(isolate, isolate->factory()->name_string(),
372 &ScriptNameGetter, nullptr);
373 }
374
375
376 //
377 // Accessors::ScriptSource
378 //
379
380
ScriptSourceGetter(v8::Local<v8::Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)381 void Accessors::ScriptSourceGetter(
382 v8::Local<v8::Name> name,
383 const v8::PropertyCallbackInfo<v8::Value>& info) {
384 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
385 DisallowHeapAllocation no_allocation;
386 HandleScope scope(isolate);
387 Object* object = *Utils::OpenHandle(*info.Holder());
388 Object* source = Script::cast(JSValue::cast(object)->value())->source();
389 info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(source, isolate)));
390 }
391
MakeScriptSourceInfo(Isolate * isolate)392 Handle<AccessorInfo> Accessors::MakeScriptSourceInfo(Isolate* isolate) {
393 return MakeAccessor(isolate, isolate->factory()->source_string(),
394 &ScriptSourceGetter, nullptr);
395 }
396
397
398 //
399 // Accessors::ScriptLineOffset
400 //
401
402
ScriptLineOffsetGetter(v8::Local<v8::Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)403 void Accessors::ScriptLineOffsetGetter(
404 v8::Local<v8::Name> name,
405 const v8::PropertyCallbackInfo<v8::Value>& info) {
406 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
407 DisallowHeapAllocation no_allocation;
408 HandleScope scope(isolate);
409 Object* object = *Utils::OpenHandle(*info.Holder());
410 Object* res =
411 Smi::FromInt(Script::cast(JSValue::cast(object)->value())->line_offset());
412 info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(res, isolate)));
413 }
414
MakeScriptLineOffsetInfo(Isolate * isolate)415 Handle<AccessorInfo> Accessors::MakeScriptLineOffsetInfo(Isolate* isolate) {
416 Handle<String> name(isolate->factory()->InternalizeOneByteString(
417 STATIC_CHAR_VECTOR("line_offset")));
418 return MakeAccessor(isolate, name, &ScriptLineOffsetGetter, nullptr);
419 }
420
421
422 //
423 // Accessors::ScriptType
424 //
425
426
ScriptTypeGetter(v8::Local<v8::Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)427 void Accessors::ScriptTypeGetter(
428 v8::Local<v8::Name> name,
429 const v8::PropertyCallbackInfo<v8::Value>& info) {
430 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
431 DisallowHeapAllocation no_allocation;
432 HandleScope scope(isolate);
433 Object* object = *Utils::OpenHandle(*info.Holder());
434 Object* res =
435 Smi::FromInt(Script::cast(JSValue::cast(object)->value())->type());
436 info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(res, isolate)));
437 }
438
MakeScriptTypeInfo(Isolate * isolate)439 Handle<AccessorInfo> Accessors::MakeScriptTypeInfo(Isolate* isolate) {
440 Handle<String> name(
441 isolate->factory()->InternalizeOneByteString(STATIC_CHAR_VECTOR("type")));
442 return MakeAccessor(isolate, name, &ScriptTypeGetter, nullptr);
443 }
444
445
446 //
447 // Accessors::ScriptCompilationType
448 //
449
450
ScriptCompilationTypeGetter(v8::Local<v8::Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)451 void Accessors::ScriptCompilationTypeGetter(
452 v8::Local<v8::Name> name,
453 const v8::PropertyCallbackInfo<v8::Value>& info) {
454 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
455 DisallowHeapAllocation no_allocation;
456 HandleScope scope(isolate);
457 Object* object = *Utils::OpenHandle(*info.Holder());
458 Object* res = Smi::FromInt(
459 Script::cast(JSValue::cast(object)->value())->compilation_type());
460 info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(res, isolate)));
461 }
462
MakeScriptCompilationTypeInfo(Isolate * isolate)463 Handle<AccessorInfo> Accessors::MakeScriptCompilationTypeInfo(
464 Isolate* isolate) {
465 Handle<String> name(isolate->factory()->InternalizeOneByteString(
466 STATIC_CHAR_VECTOR("compilation_type")));
467 return MakeAccessor(isolate, name, &ScriptCompilationTypeGetter, nullptr);
468 }
469
470
471 //
472 // Accessors::ScriptSourceUrl
473 //
474
475
ScriptSourceUrlGetter(v8::Local<v8::Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)476 void Accessors::ScriptSourceUrlGetter(
477 v8::Local<v8::Name> name,
478 const v8::PropertyCallbackInfo<v8::Value>& info) {
479 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
480 DisallowHeapAllocation no_allocation;
481 HandleScope scope(isolate);
482 Object* object = *Utils::OpenHandle(*info.Holder());
483 Object* url = Script::cast(JSValue::cast(object)->value())->source_url();
484 info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(url, isolate)));
485 }
486
MakeScriptSourceUrlInfo(Isolate * isolate)487 Handle<AccessorInfo> Accessors::MakeScriptSourceUrlInfo(Isolate* isolate) {
488 Handle<String> name(isolate->factory()->InternalizeOneByteString(
489 STATIC_CHAR_VECTOR("source_url")));
490 return MakeAccessor(isolate, name, &ScriptSourceUrlGetter, nullptr);
491 }
492
493
494 //
495 // Accessors::ScriptSourceMappingUrl
496 //
497
498
ScriptSourceMappingUrlGetter(v8::Local<v8::Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)499 void Accessors::ScriptSourceMappingUrlGetter(
500 v8::Local<v8::Name> name,
501 const v8::PropertyCallbackInfo<v8::Value>& info) {
502 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
503 DisallowHeapAllocation no_allocation;
504 HandleScope scope(isolate);
505 Object* object = *Utils::OpenHandle(*info.Holder());
506 Object* url =
507 Script::cast(JSValue::cast(object)->value())->source_mapping_url();
508 info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(url, isolate)));
509 }
510
MakeScriptSourceMappingUrlInfo(Isolate * isolate)511 Handle<AccessorInfo> Accessors::MakeScriptSourceMappingUrlInfo(
512 Isolate* isolate) {
513 Handle<String> name(isolate->factory()->InternalizeOneByteString(
514 STATIC_CHAR_VECTOR("source_mapping_url")));
515 return MakeAccessor(isolate, name, &ScriptSourceMappingUrlGetter, nullptr);
516 }
517
518
519 //
520 // Accessors::ScriptGetContextData
521 //
522
523
ScriptContextDataGetter(v8::Local<v8::Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)524 void Accessors::ScriptContextDataGetter(
525 v8::Local<v8::Name> name,
526 const v8::PropertyCallbackInfo<v8::Value>& info) {
527 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
528 DisallowHeapAllocation no_allocation;
529 HandleScope scope(isolate);
530 Object* object = *Utils::OpenHandle(*info.Holder());
531 Object* res = Script::cast(JSValue::cast(object)->value())->context_data();
532 info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(res, isolate)));
533 }
534
MakeScriptContextDataInfo(Isolate * isolate)535 Handle<AccessorInfo> Accessors::MakeScriptContextDataInfo(Isolate* isolate) {
536 Handle<String> name(isolate->factory()->InternalizeOneByteString(
537 STATIC_CHAR_VECTOR("context_data")));
538 return MakeAccessor(isolate, name, &ScriptContextDataGetter, nullptr);
539 }
540
541
542 //
543 // Accessors::ScriptGetEvalFromScript
544 //
545
546
ScriptEvalFromScriptGetter(v8::Local<v8::Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)547 void Accessors::ScriptEvalFromScriptGetter(
548 v8::Local<v8::Name> name,
549 const v8::PropertyCallbackInfo<v8::Value>& info) {
550 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
551 HandleScope scope(isolate);
552 Handle<Object> object = Utils::OpenHandle(*info.Holder());
553 Handle<Script> script(
554 Script::cast(Handle<JSValue>::cast(object)->value()), isolate);
555 Handle<Object> result = isolate->factory()->undefined_value();
556 if (script->has_eval_from_shared()) {
557 Handle<SharedFunctionInfo> eval_from_shared(script->eval_from_shared());
558 if (eval_from_shared->script()->IsScript()) {
559 Handle<Script> eval_from_script(Script::cast(eval_from_shared->script()));
560 result = Script::GetWrapper(eval_from_script);
561 }
562 }
563
564 info.GetReturnValue().Set(Utils::ToLocal(result));
565 }
566
MakeScriptEvalFromScriptInfo(Isolate * isolate)567 Handle<AccessorInfo> Accessors::MakeScriptEvalFromScriptInfo(Isolate* isolate) {
568 Handle<String> name(isolate->factory()->InternalizeOneByteString(
569 STATIC_CHAR_VECTOR("eval_from_script")));
570 return MakeAccessor(isolate, name, &ScriptEvalFromScriptGetter, nullptr);
571 }
572
573
574 //
575 // Accessors::ScriptGetEvalFromScriptPosition
576 //
577
578
ScriptEvalFromScriptPositionGetter(v8::Local<v8::Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)579 void Accessors::ScriptEvalFromScriptPositionGetter(
580 v8::Local<v8::Name> name,
581 const v8::PropertyCallbackInfo<v8::Value>& info) {
582 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
583 HandleScope scope(isolate);
584 Handle<Object> object = Utils::OpenHandle(*info.Holder());
585 Handle<Script> script(
586 Script::cast(Handle<JSValue>::cast(object)->value()), isolate);
587 Handle<Object> result = isolate->factory()->undefined_value();
588 if (script->compilation_type() == Script::COMPILATION_TYPE_EVAL) {
589 result = Handle<Object>(Smi::FromInt(script->GetEvalPosition()), isolate);
590 }
591 info.GetReturnValue().Set(Utils::ToLocal(result));
592 }
593
MakeScriptEvalFromScriptPositionInfo(Isolate * isolate)594 Handle<AccessorInfo> Accessors::MakeScriptEvalFromScriptPositionInfo(
595 Isolate* isolate) {
596 Handle<String> name(isolate->factory()->InternalizeOneByteString(
597 STATIC_CHAR_VECTOR("eval_from_script_position")));
598 return MakeAccessor(isolate, name, &ScriptEvalFromScriptPositionGetter,
599 nullptr);
600 }
601
602
603 //
604 // Accessors::ScriptGetEvalFromFunctionName
605 //
606
607
ScriptEvalFromFunctionNameGetter(v8::Local<v8::Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)608 void Accessors::ScriptEvalFromFunctionNameGetter(
609 v8::Local<v8::Name> name,
610 const v8::PropertyCallbackInfo<v8::Value>& info) {
611 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
612 HandleScope scope(isolate);
613 Handle<Object> object = Utils::OpenHandle(*info.Holder());
614 Handle<Script> script(
615 Script::cast(Handle<JSValue>::cast(object)->value()), isolate);
616 Handle<Object> result = isolate->factory()->undefined_value();
617 if (script->has_eval_from_shared()) {
618 Handle<SharedFunctionInfo> shared(script->eval_from_shared());
619 // Find the name of the function calling eval.
620 result = Handle<Object>(shared->Name(), isolate);
621 }
622 info.GetReturnValue().Set(Utils::ToLocal(result));
623 }
624
MakeScriptEvalFromFunctionNameInfo(Isolate * isolate)625 Handle<AccessorInfo> Accessors::MakeScriptEvalFromFunctionNameInfo(
626 Isolate* isolate) {
627 Handle<String> name(isolate->factory()->InternalizeOneByteString(
628 STATIC_CHAR_VECTOR("eval_from_function_name")));
629 return MakeAccessor(isolate, name, &ScriptEvalFromFunctionNameGetter,
630 nullptr);
631 }
632
633
634 //
635 // Accessors::FunctionPrototype
636 //
637
GetFunctionPrototype(Isolate * isolate,Handle<JSFunction> function)638 static Handle<Object> GetFunctionPrototype(Isolate* isolate,
639 Handle<JSFunction> function) {
640 if (!function->has_prototype()) {
641 Handle<Object> proto = isolate->factory()->NewFunctionPrototype(function);
642 JSFunction::SetPrototype(function, proto);
643 }
644 return Handle<Object>(function->prototype(), isolate);
645 }
646
FunctionPrototypeGetter(v8::Local<v8::Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)647 void Accessors::FunctionPrototypeGetter(
648 v8::Local<v8::Name> name,
649 const v8::PropertyCallbackInfo<v8::Value>& info) {
650 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
651 RuntimeCallTimerScope timer(isolate,
652 RuntimeCallCounterId::kFunctionPrototypeGetter);
653 HandleScope scope(isolate);
654 Handle<JSFunction> function =
655 Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
656 Handle<Object> result = GetFunctionPrototype(isolate, function);
657 info.GetReturnValue().Set(Utils::ToLocal(result));
658 }
659
FunctionPrototypeSetter(v8::Local<v8::Name> name,v8::Local<v8::Value> val,const v8::PropertyCallbackInfo<v8::Boolean> & info)660 void Accessors::FunctionPrototypeSetter(
661 v8::Local<v8::Name> name, v8::Local<v8::Value> val,
662 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
663 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
664 RuntimeCallTimerScope timer(isolate,
665 RuntimeCallCounterId::kFunctionPrototypeSetter);
666 HandleScope scope(isolate);
667 Handle<Object> value = Utils::OpenHandle(*val);
668 Handle<JSFunction> object =
669 Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
670 JSFunction::SetPrototype(object, value);
671 info.GetReturnValue().Set(true);
672 }
673
MakeFunctionPrototypeInfo(Isolate * isolate)674 Handle<AccessorInfo> Accessors::MakeFunctionPrototypeInfo(Isolate* isolate) {
675 return MakeAccessor(isolate, isolate->factory()->prototype_string(),
676 &FunctionPrototypeGetter, &FunctionPrototypeSetter);
677 }
678
679
680 //
681 // Accessors::FunctionLength
682 //
683
684
FunctionLengthGetter(v8::Local<v8::Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)685 void Accessors::FunctionLengthGetter(
686 v8::Local<v8::Name> name,
687 const v8::PropertyCallbackInfo<v8::Value>& info) {
688 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
689 RuntimeCallTimerScope timer(isolate,
690 RuntimeCallCounterId::kFunctionLengthGetter);
691 HandleScope scope(isolate);
692 Handle<JSFunction> function =
693 Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
694 int length = 0;
695 if (!JSFunction::GetLength(isolate, function).To(&length)) {
696 isolate->OptionalRescheduleException(false);
697 }
698 Handle<Object> result(Smi::FromInt(length), isolate);
699 info.GetReturnValue().Set(Utils::ToLocal(result));
700 }
701
MakeFunctionLengthInfo(Isolate * isolate)702 Handle<AccessorInfo> Accessors::MakeFunctionLengthInfo(Isolate* isolate) {
703 return MakeAccessor(isolate, isolate->factory()->length_string(),
704 &FunctionLengthGetter, &ReconfigureToDataProperty);
705 }
706
707
708 //
709 // Accessors::FunctionName
710 //
711
712
FunctionNameGetter(v8::Local<v8::Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)713 void Accessors::FunctionNameGetter(
714 v8::Local<v8::Name> name,
715 const v8::PropertyCallbackInfo<v8::Value>& info) {
716 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
717 HandleScope scope(isolate);
718 Handle<JSFunction> function =
719 Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
720 Handle<Object> result = JSFunction::GetName(isolate, function);
721 info.GetReturnValue().Set(Utils::ToLocal(result));
722 }
723
MakeFunctionNameInfo(Isolate * isolate)724 Handle<AccessorInfo> Accessors::MakeFunctionNameInfo(Isolate* isolate) {
725 return MakeAccessor(isolate, isolate->factory()->name_string(),
726 &FunctionNameGetter, &ReconfigureToDataProperty);
727 }
728
729
730 //
731 // Accessors::FunctionArguments
732 //
733
734 namespace {
735
ArgumentsForInlinedFunction(JavaScriptFrame * frame,int inlined_frame_index)736 Handle<JSObject> ArgumentsForInlinedFunction(JavaScriptFrame* frame,
737 int inlined_frame_index) {
738 Isolate* isolate = frame->isolate();
739 Factory* factory = isolate->factory();
740
741 TranslatedState translated_values(frame);
742 translated_values.Prepare(frame->fp());
743
744 int argument_count = 0;
745 TranslatedFrame* translated_frame =
746 translated_values.GetArgumentsInfoFromJSFrameIndex(inlined_frame_index,
747 &argument_count);
748 TranslatedFrame::iterator iter = translated_frame->begin();
749
750 // Materialize the function.
751 bool should_deoptimize = iter->IsMaterializedObject();
752 Handle<JSFunction> function = Handle<JSFunction>::cast(iter->GetValue());
753 iter++;
754
755 // Skip the receiver.
756 iter++;
757 argument_count--;
758
759 Handle<JSObject> arguments =
760 factory->NewArgumentsObject(function, argument_count);
761 Handle<FixedArray> array = factory->NewFixedArray(argument_count);
762 for (int i = 0; i < argument_count; ++i) {
763 // If we materialize any object, we should deoptimize the frame because we
764 // might alias an object that was eliminated by escape analysis.
765 should_deoptimize = should_deoptimize || iter->IsMaterializedObject();
766 Handle<Object> value = iter->GetValue();
767 array->set(i, *value);
768 iter++;
769 }
770 arguments->set_elements(*array);
771
772 if (should_deoptimize) {
773 translated_values.StoreMaterializedValuesAndDeopt(frame);
774 }
775
776 // Return the freshly allocated arguments object.
777 return arguments;
778 }
779
FindFunctionInFrame(JavaScriptFrame * frame,Handle<JSFunction> function)780 int FindFunctionInFrame(JavaScriptFrame* frame, Handle<JSFunction> function) {
781 std::vector<FrameSummary> frames;
782 frame->Summarize(&frames);
783 for (size_t i = frames.size(); i != 0; i--) {
784 if (*frames[i - 1].AsJavaScript().function() == *function) {
785 return static_cast<int>(i) - 1;
786 }
787 }
788 return -1;
789 }
790
GetFrameArguments(Isolate * isolate,JavaScriptFrameIterator * it,int function_index)791 Handle<JSObject> GetFrameArguments(Isolate* isolate,
792 JavaScriptFrameIterator* it,
793 int function_index) {
794 JavaScriptFrame* frame = it->frame();
795
796 if (function_index > 0) {
797 // The function in question was inlined. Inlined functions have the
798 // correct number of arguments and no allocated arguments object, so
799 // we can construct a fresh one by interpreting the function's
800 // deoptimization input data.
801 return ArgumentsForInlinedFunction(frame, function_index);
802 }
803
804 // Find the frame that holds the actual arguments passed to the function.
805 if (it->frame()->has_adapted_arguments()) {
806 it->AdvanceOneFrame();
807 DCHECK(it->frame()->is_arguments_adaptor());
808 }
809 frame = it->frame();
810
811 // Get the number of arguments and construct an arguments object
812 // mirror for the right frame and the underlying function.
813 const int length = frame->ComputeParametersCount();
814 Handle<JSFunction> function(frame->function(), isolate);
815 Handle<JSObject> arguments =
816 isolate->factory()->NewArgumentsObject(function, length);
817 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
818
819 // Copy the parameters to the arguments object.
820 DCHECK(array->length() == length);
821 for (int i = 0; i < length; i++) {
822 Object* value = frame->GetParameter(i);
823 if (value->IsTheHole(isolate)) {
824 // Generators currently use holes as dummy arguments when resuming. We
825 // must not leak those.
826 DCHECK(IsResumableFunction(function->shared()->kind()));
827 value = isolate->heap()->undefined_value();
828 }
829 array->set(i, value);
830 }
831 arguments->set_elements(*array);
832
833 // Return the freshly allocated arguments object.
834 return arguments;
835 }
836
837 } // namespace
838
FunctionGetArguments(JavaScriptFrame * frame,int inlined_jsframe_index)839 Handle<JSObject> Accessors::FunctionGetArguments(JavaScriptFrame* frame,
840 int inlined_jsframe_index) {
841 Isolate* isolate = frame->isolate();
842 Address requested_frame_fp = frame->fp();
843 // Forward a frame iterator to the requested frame. This is needed because we
844 // potentially need for advance it to the arguments adaptor frame later.
845 for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) {
846 if (it.frame()->fp() != requested_frame_fp) continue;
847 return GetFrameArguments(isolate, &it, inlined_jsframe_index);
848 }
849 UNREACHABLE(); // Requested frame not found.
850 return Handle<JSObject>();
851 }
852
853
FunctionArgumentsGetter(v8::Local<v8::Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)854 void Accessors::FunctionArgumentsGetter(
855 v8::Local<v8::Name> name,
856 const v8::PropertyCallbackInfo<v8::Value>& info) {
857 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
858 HandleScope scope(isolate);
859 Handle<JSFunction> function =
860 Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
861 Handle<Object> result = isolate->factory()->null_value();
862 if (!function->shared()->native()) {
863 // Find the top invocation of the function by traversing frames.
864 for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) {
865 JavaScriptFrame* frame = it.frame();
866 int function_index = FindFunctionInFrame(frame, function);
867 if (function_index >= 0) {
868 result = GetFrameArguments(isolate, &it, function_index);
869 break;
870 }
871 }
872 }
873 info.GetReturnValue().Set(Utils::ToLocal(result));
874 }
875
MakeFunctionArgumentsInfo(Isolate * isolate)876 Handle<AccessorInfo> Accessors::MakeFunctionArgumentsInfo(Isolate* isolate) {
877 return MakeAccessor(isolate, isolate->factory()->arguments_string(),
878 &FunctionArgumentsGetter, nullptr);
879 }
880
881
882 //
883 // Accessors::FunctionCaller
884 //
885
886
AllowAccessToFunction(Context * current_context,JSFunction * function)887 static inline bool AllowAccessToFunction(Context* current_context,
888 JSFunction* function) {
889 return current_context->HasSameSecurityTokenAs(function->context());
890 }
891
892
893 class FrameFunctionIterator {
894 public:
FrameFunctionIterator(Isolate * isolate)895 explicit FrameFunctionIterator(Isolate* isolate)
896 : isolate_(isolate), frame_iterator_(isolate), inlined_frame_index_(-1) {
897 GetFrames();
898 }
899
900 // Iterate through functions until the first occurrence of 'function'.
901 // Returns true if one is found, and false if the iterator ends before.
Find(Handle<JSFunction> function)902 bool Find(Handle<JSFunction> function) {
903 do {
904 if (!next().ToHandle(&function_)) return false;
905 } while (!function_.is_identical_to(function));
906 return true;
907 }
908
909 // Iterate through functions until the next non-toplevel one is found.
910 // Returns true if one is found, and false if the iterator ends before.
FindNextNonTopLevel()911 bool FindNextNonTopLevel() {
912 do {
913 if (!next().ToHandle(&function_)) return false;
914 } while (function_->shared()->is_toplevel());
915 return true;
916 }
917
918 // Iterate through function until the first native or user-provided function
919 // is found. Functions not defined in user-provided scripts are not visible
920 // unless directly exposed, in which case the native flag is set on them.
921 // Returns true if one is found, and false if the iterator ends before.
FindFirstNativeOrUserJavaScript()922 bool FindFirstNativeOrUserJavaScript() {
923 while (!function_->shared()->native() &&
924 !function_->shared()->IsUserJavaScript()) {
925 if (!next().ToHandle(&function_)) return false;
926 }
927 return true;
928 }
929
930 // In case of inlined frames the function could have been materialized from
931 // deoptimization information. If that is the case we need to make sure that
932 // subsequent call will see the same function, since we are about to hand out
933 // the value to JavaScript. Make sure to store the materialized value and
934 // trigger a deoptimization of the underlying frame.
MaterializeFunction()935 Handle<JSFunction> MaterializeFunction() {
936 if (inlined_frame_index_ == 0) return function_;
937
938 JavaScriptFrame* frame = frame_iterator_.frame();
939 TranslatedState translated_values(frame);
940 translated_values.Prepare(frame->fp());
941
942 TranslatedFrame* translated_frame =
943 translated_values.GetFrameFromJSFrameIndex(inlined_frame_index_);
944 TranslatedFrame::iterator iter = translated_frame->begin();
945
946 // First value is the function.
947 bool should_deoptimize = iter->IsMaterializedObject();
948 Handle<Object> value = iter->GetValue();
949 if (should_deoptimize) {
950 translated_values.StoreMaterializedValuesAndDeopt(frame);
951 }
952
953 return Handle<JSFunction>::cast(value);
954 }
955
956 private:
next()957 MaybeHandle<JSFunction> next() {
958 while (true) {
959 if (inlined_frame_index_ <= 0) {
960 if (!frame_iterator_.done()) {
961 frame_iterator_.Advance();
962 frames_.clear();
963 inlined_frame_index_ = -1;
964 GetFrames();
965 }
966 if (inlined_frame_index_ == -1) return MaybeHandle<JSFunction>();
967 }
968
969 --inlined_frame_index_;
970 Handle<JSFunction> next_function =
971 frames_[inlined_frame_index_].AsJavaScript().function();
972 // Skip functions from other origins.
973 if (!AllowAccessToFunction(isolate_->context(), *next_function)) continue;
974 return next_function;
975 }
976 }
GetFrames()977 void GetFrames() {
978 DCHECK_EQ(-1, inlined_frame_index_);
979 if (frame_iterator_.done()) return;
980 JavaScriptFrame* frame = frame_iterator_.frame();
981 frame->Summarize(&frames_);
982 inlined_frame_index_ = static_cast<int>(frames_.size());
983 DCHECK_LT(0, inlined_frame_index_);
984 }
985 Isolate* isolate_;
986 Handle<JSFunction> function_;
987 JavaScriptFrameIterator frame_iterator_;
988 std::vector<FrameSummary> frames_;
989 int inlined_frame_index_;
990 };
991
992
FindCaller(Isolate * isolate,Handle<JSFunction> function)993 MaybeHandle<JSFunction> FindCaller(Isolate* isolate,
994 Handle<JSFunction> function) {
995 FrameFunctionIterator it(isolate);
996 if (function->shared()->native()) {
997 return MaybeHandle<JSFunction>();
998 }
999 // Find the function from the frames. Return null in case no frame
1000 // corresponding to the given function was found.
1001 if (!it.Find(function)) {
1002 return MaybeHandle<JSFunction>();
1003 }
1004 // Find previously called non-toplevel function.
1005 if (!it.FindNextNonTopLevel()) {
1006 return MaybeHandle<JSFunction>();
1007 }
1008 // Find the first user-land JavaScript function (or the entry point into
1009 // native JavaScript builtins in case such a builtin was the caller).
1010 if (!it.FindFirstNativeOrUserJavaScript()) {
1011 return MaybeHandle<JSFunction>();
1012 }
1013
1014 // Materialize the function that the iterator is currently sitting on. Note
1015 // that this might trigger deoptimization in case the function was actually
1016 // materialized. Identity of the function must be preserved because we are
1017 // going to return it to JavaScript after this point.
1018 Handle<JSFunction> caller = it.MaterializeFunction();
1019
1020 // Censor if the caller is not a sloppy mode function.
1021 // Change from ES5, which used to throw, see:
1022 // https://bugs.ecmascript.org/show_bug.cgi?id=310
1023 if (is_strict(caller->shared()->language_mode())) {
1024 return MaybeHandle<JSFunction>();
1025 }
1026 // Don't return caller from another security context.
1027 if (!AllowAccessToFunction(isolate->context(), *caller)) {
1028 return MaybeHandle<JSFunction>();
1029 }
1030 return caller;
1031 }
1032
1033
FunctionCallerGetter(v8::Local<v8::Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)1034 void Accessors::FunctionCallerGetter(
1035 v8::Local<v8::Name> name,
1036 const v8::PropertyCallbackInfo<v8::Value>& info) {
1037 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
1038 HandleScope scope(isolate);
1039 Handle<JSFunction> function =
1040 Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
1041 Handle<Object> result;
1042 MaybeHandle<JSFunction> maybe_caller;
1043 maybe_caller = FindCaller(isolate, function);
1044 Handle<JSFunction> caller;
1045 if (maybe_caller.ToHandle(&caller)) {
1046 result = caller;
1047 } else {
1048 result = isolate->factory()->null_value();
1049 }
1050 info.GetReturnValue().Set(Utils::ToLocal(result));
1051 }
1052
MakeFunctionCallerInfo(Isolate * isolate)1053 Handle<AccessorInfo> Accessors::MakeFunctionCallerInfo(Isolate* isolate) {
1054 return MakeAccessor(isolate, isolate->factory()->caller_string(),
1055 &FunctionCallerGetter, nullptr);
1056 }
1057
1058
1059 //
1060 // Accessors::BoundFunctionLength
1061 //
1062
BoundFunctionLengthGetter(v8::Local<v8::Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)1063 void Accessors::BoundFunctionLengthGetter(
1064 v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
1065 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
1066 RuntimeCallTimerScope timer(isolate,
1067 RuntimeCallCounterId::kBoundFunctionLengthGetter);
1068 HandleScope scope(isolate);
1069 Handle<JSBoundFunction> function =
1070 Handle<JSBoundFunction>::cast(Utils::OpenHandle(*info.Holder()));
1071
1072 int length = 0;
1073 if (!JSBoundFunction::GetLength(isolate, function).To(&length)) {
1074 isolate->OptionalRescheduleException(false);
1075 return;
1076 }
1077 Handle<Object> result(Smi::FromInt(length), isolate);
1078 info.GetReturnValue().Set(Utils::ToLocal(result));
1079 }
1080
MakeBoundFunctionLengthInfo(Isolate * isolate)1081 Handle<AccessorInfo> Accessors::MakeBoundFunctionLengthInfo(Isolate* isolate) {
1082 return MakeAccessor(isolate, isolate->factory()->length_string(),
1083 &BoundFunctionLengthGetter, &ReconfigureToDataProperty);
1084 }
1085
1086 //
1087 // Accessors::BoundFunctionName
1088 //
1089
BoundFunctionNameGetter(v8::Local<v8::Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)1090 void Accessors::BoundFunctionNameGetter(
1091 v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
1092 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
1093 RuntimeCallTimerScope timer(isolate,
1094 RuntimeCallCounterId::kBoundFunctionNameGetter);
1095 HandleScope scope(isolate);
1096 Handle<JSBoundFunction> function =
1097 Handle<JSBoundFunction>::cast(Utils::OpenHandle(*info.Holder()));
1098 Handle<Object> result;
1099 if (!JSBoundFunction::GetName(isolate, function).ToHandle(&result)) {
1100 isolate->OptionalRescheduleException(false);
1101 return;
1102 }
1103 info.GetReturnValue().Set(Utils::ToLocal(result));
1104 }
1105
MakeBoundFunctionNameInfo(Isolate * isolate)1106 Handle<AccessorInfo> Accessors::MakeBoundFunctionNameInfo(Isolate* isolate) {
1107 return MakeAccessor(isolate, isolate->factory()->name_string(),
1108 &BoundFunctionNameGetter, &ReconfigureToDataProperty);
1109 }
1110
1111 //
1112 // Accessors::ErrorStack
1113 //
1114
1115 namespace {
1116
ClearInternalStackTrace(Isolate * isolate,Handle<JSObject> error)1117 MaybeHandle<JSReceiver> ClearInternalStackTrace(Isolate* isolate,
1118 Handle<JSObject> error) {
1119 RETURN_ON_EXCEPTION(
1120 isolate,
1121 JSReceiver::SetProperty(error, isolate->factory()->stack_trace_symbol(),
1122 isolate->factory()->undefined_value(),
1123 LanguageMode::kStrict),
1124 JSReceiver);
1125 return error;
1126 }
1127
IsAccessor(Handle<Object> receiver,Handle<Name> name,Handle<JSObject> holder)1128 bool IsAccessor(Handle<Object> receiver, Handle<Name> name,
1129 Handle<JSObject> holder) {
1130 LookupIterator it(receiver, name, holder,
1131 LookupIterator::OWN_SKIP_INTERCEPTOR);
1132 // Skip any access checks we might hit. This accessor should never hit in a
1133 // situation where the caller does not have access.
1134 if (it.state() == LookupIterator::ACCESS_CHECK) {
1135 CHECK(it.HasAccess());
1136 it.Next();
1137 }
1138 return (it.state() == LookupIterator::ACCESSOR);
1139 }
1140
1141 } // namespace
1142
ErrorStackGetter(v8::Local<v8::Name> key,const v8::PropertyCallbackInfo<v8::Value> & info)1143 void Accessors::ErrorStackGetter(
1144 v8::Local<v8::Name> key, const v8::PropertyCallbackInfo<v8::Value>& info) {
1145 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
1146 HandleScope scope(isolate);
1147 Handle<JSObject> holder =
1148 Handle<JSObject>::cast(Utils::OpenHandle(*info.Holder()));
1149
1150 // Retrieve the structured stack trace.
1151
1152 Handle<Object> stack_trace;
1153 Handle<Symbol> stack_trace_symbol = isolate->factory()->stack_trace_symbol();
1154 MaybeHandle<Object> maybe_stack_trace =
1155 JSObject::GetProperty(holder, stack_trace_symbol);
1156 if (!maybe_stack_trace.ToHandle(&stack_trace) ||
1157 stack_trace->IsUndefined(isolate)) {
1158 Handle<Object> result = isolate->factory()->undefined_value();
1159 info.GetReturnValue().Set(Utils::ToLocal(result));
1160 return;
1161 }
1162
1163 // Format it, clear the internal structured trace and reconfigure as a data
1164 // property.
1165
1166 Handle<Object> formatted_stack_trace;
1167 if (!ErrorUtils::FormatStackTrace(isolate, holder, stack_trace)
1168 .ToHandle(&formatted_stack_trace)) {
1169 isolate->OptionalRescheduleException(false);
1170 return;
1171 }
1172
1173 MaybeHandle<Object> result = ClearInternalStackTrace(isolate, holder);
1174 if (result.is_null()) {
1175 isolate->OptionalRescheduleException(false);
1176 return;
1177 }
1178
1179 // If stack is still an accessor (this could have changed in the meantime
1180 // since FormatStackTrace can execute arbitrary JS), replace it with a data
1181 // property.
1182 Handle<Object> receiver =
1183 Utils::OpenHandle(*v8::Local<v8::Value>(info.This()));
1184 Handle<Name> name = Utils::OpenHandle(*key);
1185 if (IsAccessor(receiver, name, holder)) {
1186 result = Accessors::ReplaceAccessorWithDataProperty(
1187 isolate, receiver, holder, name, formatted_stack_trace);
1188 if (result.is_null()) {
1189 isolate->OptionalRescheduleException(false);
1190 return;
1191 }
1192 } else {
1193 // The stack property has been modified in the meantime.
1194 if (!JSObject::GetProperty(holder, name).ToHandle(&formatted_stack_trace)) {
1195 isolate->OptionalRescheduleException(false);
1196 return;
1197 }
1198 }
1199
1200 v8::Local<v8::Value> value = Utils::ToLocal(formatted_stack_trace);
1201 info.GetReturnValue().Set(value);
1202 }
1203
ErrorStackSetter(v8::Local<v8::Name> name,v8::Local<v8::Value> val,const v8::PropertyCallbackInfo<v8::Boolean> & info)1204 void Accessors::ErrorStackSetter(
1205 v8::Local<v8::Name> name, v8::Local<v8::Value> val,
1206 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
1207 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
1208 HandleScope scope(isolate);
1209 Handle<JSObject> obj = Handle<JSObject>::cast(
1210 Utils::OpenHandle(*v8::Local<v8::Value>(info.This())));
1211
1212 // Clear internal properties to avoid memory leaks.
1213 Handle<Symbol> stack_trace_symbol = isolate->factory()->stack_trace_symbol();
1214 if (JSReceiver::HasOwnProperty(obj, stack_trace_symbol).FromMaybe(false)) {
1215 ClearInternalStackTrace(isolate, obj);
1216 }
1217
1218 Accessors::ReconfigureToDataProperty(name, val, info);
1219 }
1220
MakeErrorStackInfo(Isolate * isolate)1221 Handle<AccessorInfo> Accessors::MakeErrorStackInfo(Isolate* isolate) {
1222 return MakeAccessor(isolate, isolate->factory()->stack_string(),
1223 &ErrorStackGetter, &ErrorStackSetter);
1224 }
1225
1226 } // namespace internal
1227 } // namespace v8
1228