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/v8.h"
6 #include "src/accessors.h"
7
8 #include "src/compiler.h"
9 #include "src/contexts.h"
10 #include "src/deoptimizer.h"
11 #include "src/execution.h"
12 #include "src/factory.h"
13 #include "src/frames-inl.h"
14 #include "src/isolate.h"
15 #include "src/list-inl.h"
16 #include "src/property-details.h"
17 #include "src/api.h"
18
19 namespace v8 {
20 namespace internal {
21
22
23 // We have a slight impedance mismatch between the external API and the way we
24 // use callbacks internally: Externally, callbacks can only be used with
25 // v8::Object, but internally we even have callbacks on entities which are
26 // higher in the hierarchy, so we can only return i::Object here, not
27 // i::JSObject.
GetThisFrom(const v8::PropertyCallbackInfo<v8::Value> & info)28 Handle<Object> GetThisFrom(const v8::PropertyCallbackInfo<v8::Value>& info) {
29 return Utils::OpenHandle(*v8::Local<v8::Value>(info.This()));
30 }
31
32
MakeAccessor(Isolate * isolate,Handle<String> name,AccessorGetterCallback getter,AccessorSetterCallback setter,PropertyAttributes attributes)33 Handle<AccessorInfo> Accessors::MakeAccessor(
34 Isolate* isolate,
35 Handle<String> name,
36 AccessorGetterCallback getter,
37 AccessorSetterCallback setter,
38 PropertyAttributes attributes) {
39 Factory* factory = isolate->factory();
40 Handle<ExecutableAccessorInfo> info = factory->NewExecutableAccessorInfo();
41 info->set_property_attributes(attributes);
42 info->set_all_can_read(false);
43 info->set_all_can_write(false);
44 info->set_name(*name);
45 Handle<Object> get = v8::FromCData(isolate, getter);
46 Handle<Object> set = v8::FromCData(isolate, setter);
47 info->set_getter(*get);
48 info->set_setter(*set);
49 return info;
50 }
51
52
CloneAccessor(Isolate * isolate,Handle<ExecutableAccessorInfo> accessor)53 Handle<ExecutableAccessorInfo> Accessors::CloneAccessor(
54 Isolate* isolate,
55 Handle<ExecutableAccessorInfo> accessor) {
56 Factory* factory = isolate->factory();
57 Handle<ExecutableAccessorInfo> info = factory->NewExecutableAccessorInfo();
58 info->set_name(accessor->name());
59 info->set_flag(accessor->flag());
60 info->set_expected_receiver_type(accessor->expected_receiver_type());
61 info->set_getter(accessor->getter());
62 info->set_setter(accessor->setter());
63 info->set_data(accessor->data());
64 return info;
65 }
66
67
68 template <class C>
FindInstanceOf(Isolate * isolate,Object * obj)69 static C* FindInstanceOf(Isolate* isolate, Object* obj) {
70 for (Object* cur = obj; !cur->IsNull(); cur = cur->GetPrototype(isolate)) {
71 if (Is<C>(cur)) return C::cast(cur);
72 }
73 return NULL;
74 }
75
76
CheckForName(Handle<String> name,Handle<String> property_name,int offset,int * object_offset)77 static V8_INLINE bool CheckForName(Handle<String> name,
78 Handle<String> property_name,
79 int offset,
80 int* object_offset) {
81 if (String::Equals(name, property_name)) {
82 *object_offset = offset;
83 return true;
84 }
85 return false;
86 }
87
88
89 // Returns true for properties that are accessors to object fields.
90 // If true, *object_offset contains offset of object field.
91 template <class T>
IsJSObjectFieldAccessor(typename T::TypeHandle type,Handle<String> name,int * object_offset)92 bool Accessors::IsJSObjectFieldAccessor(typename T::TypeHandle type,
93 Handle<String> name,
94 int* object_offset) {
95 Isolate* isolate = name->GetIsolate();
96
97 if (type->Is(T::String())) {
98 return CheckForName(name, isolate->factory()->length_string(),
99 String::kLengthOffset, object_offset);
100 }
101
102 if (!type->IsClass()) return false;
103 Handle<Map> map = type->AsClass()->Map();
104
105 switch (map->instance_type()) {
106 case JS_ARRAY_TYPE:
107 return
108 CheckForName(name, isolate->factory()->length_string(),
109 JSArray::kLengthOffset, object_offset);
110 case JS_TYPED_ARRAY_TYPE:
111 return
112 CheckForName(name, isolate->factory()->length_string(),
113 JSTypedArray::kLengthOffset, object_offset) ||
114 CheckForName(name, isolate->factory()->byte_length_string(),
115 JSTypedArray::kByteLengthOffset, object_offset) ||
116 CheckForName(name, isolate->factory()->byte_offset_string(),
117 JSTypedArray::kByteOffsetOffset, object_offset);
118 case JS_ARRAY_BUFFER_TYPE:
119 return
120 CheckForName(name, isolate->factory()->byte_length_string(),
121 JSArrayBuffer::kByteLengthOffset, object_offset);
122 case JS_DATA_VIEW_TYPE:
123 return
124 CheckForName(name, isolate->factory()->byte_length_string(),
125 JSDataView::kByteLengthOffset, object_offset) ||
126 CheckForName(name, isolate->factory()->byte_offset_string(),
127 JSDataView::kByteOffsetOffset, object_offset);
128 default:
129 return false;
130 }
131 }
132
133
134 template
135 bool Accessors::IsJSObjectFieldAccessor<Type>(Type* type,
136 Handle<String> name,
137 int* object_offset);
138
139
140 template
141 bool Accessors::IsJSObjectFieldAccessor<HeapType>(Handle<HeapType> type,
142 Handle<String> name,
143 int* object_offset);
144
145
146 //
147 // Accessors::ArrayLength
148 //
149
150
151 // The helper function will 'flatten' Number objects.
FlattenNumber(Isolate * isolate,Handle<Object> value)152 Handle<Object> Accessors::FlattenNumber(Isolate* isolate,
153 Handle<Object> value) {
154 if (value->IsNumber() || !value->IsJSValue()) return value;
155 Handle<JSValue> wrapper = Handle<JSValue>::cast(value);
156 ASSERT(wrapper->GetIsolate()->context()->native_context()->number_function()->
157 has_initial_map());
158 if (wrapper->map() ==
159 isolate->context()->native_context()->number_function()->initial_map()) {
160 return handle(wrapper->value(), isolate);
161 }
162
163 return value;
164 }
165
166
ArrayLengthGetter(v8::Local<v8::String> name,const v8::PropertyCallbackInfo<v8::Value> & info)167 void Accessors::ArrayLengthGetter(
168 v8::Local<v8::String> name,
169 const v8::PropertyCallbackInfo<v8::Value>& info) {
170 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
171 DisallowHeapAllocation no_allocation;
172 HandleScope scope(isolate);
173 Object* object = *GetThisFrom(info);
174 // Traverse the prototype chain until we reach an array.
175 JSArray* holder = FindInstanceOf<JSArray>(isolate, object);
176 Object* result;
177 if (holder != NULL) {
178 result = holder->length();
179 } else {
180 result = Smi::FromInt(0);
181 }
182 info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(result, isolate)));
183 }
184
185
ArrayLengthSetter(v8::Local<v8::String> name,v8::Local<v8::Value> val,const v8::PropertyCallbackInfo<void> & info)186 void Accessors::ArrayLengthSetter(
187 v8::Local<v8::String> name,
188 v8::Local<v8::Value> val,
189 const v8::PropertyCallbackInfo<void>& info) {
190 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
191 HandleScope scope(isolate);
192 Handle<JSObject> object = Handle<JSObject>::cast(
193 Utils::OpenHandle(*info.This()));
194 Handle<Object> value = Utils::OpenHandle(*val);
195 // This means one of the object's prototypes is a JSArray and the
196 // object does not have a 'length' property. Calling SetProperty
197 // causes an infinite loop.
198 if (!object->IsJSArray()) {
199 MaybeHandle<Object> maybe_result =
200 JSObject::SetOwnPropertyIgnoreAttributes(
201 object, isolate->factory()->length_string(), value, NONE);
202 maybe_result.Check();
203 return;
204 }
205
206 value = FlattenNumber(isolate, value);
207
208 Handle<JSArray> array_handle = Handle<JSArray>::cast(object);
209 MaybeHandle<Object> maybe;
210 Handle<Object> uint32_v;
211 maybe = Execution::ToUint32(isolate, value);
212 if (!maybe.ToHandle(&uint32_v)) {
213 isolate->OptionalRescheduleException(false);
214 return;
215 }
216 Handle<Object> number_v;
217 maybe = Execution::ToNumber(isolate, value);
218 if (!maybe.ToHandle(&number_v)) {
219 isolate->OptionalRescheduleException(false);
220 return;
221 }
222
223 if (uint32_v->Number() == number_v->Number()) {
224 maybe = JSArray::SetElementsLength(array_handle, uint32_v);
225 maybe.Check();
226 return;
227 }
228
229 isolate->ScheduleThrow(
230 *isolate->factory()->NewRangeError("invalid_array_length",
231 HandleVector<Object>(NULL, 0)));
232 }
233
234
ArrayLengthInfo(Isolate * isolate,PropertyAttributes attributes)235 Handle<AccessorInfo> Accessors::ArrayLengthInfo(
236 Isolate* isolate, PropertyAttributes attributes) {
237 return MakeAccessor(isolate,
238 isolate->factory()->length_string(),
239 &ArrayLengthGetter,
240 &ArrayLengthSetter,
241 attributes);
242 }
243
244
245
246 //
247 // Accessors::StringLength
248 //
249
StringLengthGetter(v8::Local<v8::String> name,const v8::PropertyCallbackInfo<v8::Value> & info)250 void Accessors::StringLengthGetter(
251 v8::Local<v8::String> name,
252 const v8::PropertyCallbackInfo<v8::Value>& info) {
253 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
254 DisallowHeapAllocation no_allocation;
255 HandleScope scope(isolate);
256 Object* value = *GetThisFrom(info);
257 Object* result;
258 if (value->IsJSValue()) value = JSValue::cast(value)->value();
259 if (value->IsString()) {
260 result = Smi::FromInt(String::cast(value)->length());
261 } else {
262 // If object is not a string we return 0 to be compatible with WebKit.
263 // Note: Firefox returns the length of ToString(object).
264 result = Smi::FromInt(0);
265 }
266 info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(result, isolate)));
267 }
268
269
StringLengthSetter(v8::Local<v8::String> name,v8::Local<v8::Value> value,const v8::PropertyCallbackInfo<void> & info)270 void Accessors::StringLengthSetter(
271 v8::Local<v8::String> name,
272 v8::Local<v8::Value> value,
273 const v8::PropertyCallbackInfo<void>& info) {
274 UNREACHABLE();
275 }
276
277
StringLengthInfo(Isolate * isolate,PropertyAttributes attributes)278 Handle<AccessorInfo> Accessors::StringLengthInfo(
279 Isolate* isolate, PropertyAttributes attributes) {
280 return MakeAccessor(isolate,
281 isolate->factory()->length_string(),
282 &StringLengthGetter,
283 &StringLengthSetter,
284 attributes);
285 }
286
287
288 //
289 // Accessors::ScriptColumnOffset
290 //
291
292
ScriptColumnOffsetGetter(v8::Local<v8::String> name,const v8::PropertyCallbackInfo<v8::Value> & info)293 void Accessors::ScriptColumnOffsetGetter(
294 v8::Local<v8::String> name,
295 const v8::PropertyCallbackInfo<v8::Value>& info) {
296 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
297 DisallowHeapAllocation no_allocation;
298 HandleScope scope(isolate);
299 Object* object = *Utils::OpenHandle(*info.This());
300 Object* res = Script::cast(JSValue::cast(object)->value())->column_offset();
301 info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(res, isolate)));
302 }
303
304
ScriptColumnOffsetSetter(v8::Local<v8::String> name,v8::Local<v8::Value> value,const v8::PropertyCallbackInfo<void> & info)305 void Accessors::ScriptColumnOffsetSetter(
306 v8::Local<v8::String> name,
307 v8::Local<v8::Value> value,
308 const v8::PropertyCallbackInfo<void>& info) {
309 UNREACHABLE();
310 }
311
312
ScriptColumnOffsetInfo(Isolate * isolate,PropertyAttributes attributes)313 Handle<AccessorInfo> Accessors::ScriptColumnOffsetInfo(
314 Isolate* isolate, PropertyAttributes attributes) {
315 Handle<String> name(isolate->factory()->InternalizeOneByteString(
316 STATIC_ASCII_VECTOR("column_offset")));
317 return MakeAccessor(isolate,
318 name,
319 &ScriptColumnOffsetGetter,
320 &ScriptColumnOffsetSetter,
321 attributes);
322 }
323
324
325 //
326 // Accessors::ScriptId
327 //
328
329
ScriptIdGetter(v8::Local<v8::String> name,const v8::PropertyCallbackInfo<v8::Value> & info)330 void Accessors::ScriptIdGetter(
331 v8::Local<v8::String> name,
332 const v8::PropertyCallbackInfo<v8::Value>& info) {
333 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
334 DisallowHeapAllocation no_allocation;
335 HandleScope scope(isolate);
336 Object* object = *Utils::OpenHandle(*info.This());
337 Object* id = Script::cast(JSValue::cast(object)->value())->id();
338 info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(id, isolate)));
339 }
340
341
ScriptIdSetter(v8::Local<v8::String> name,v8::Local<v8::Value> value,const v8::PropertyCallbackInfo<void> & info)342 void Accessors::ScriptIdSetter(
343 v8::Local<v8::String> name,
344 v8::Local<v8::Value> value,
345 const v8::PropertyCallbackInfo<void>& info) {
346 UNREACHABLE();
347 }
348
349
ScriptIdInfo(Isolate * isolate,PropertyAttributes attributes)350 Handle<AccessorInfo> Accessors::ScriptIdInfo(
351 Isolate* isolate, PropertyAttributes attributes) {
352 Handle<String> name(isolate->factory()->InternalizeOneByteString(
353 STATIC_ASCII_VECTOR("id")));
354 return MakeAccessor(isolate,
355 name,
356 &ScriptIdGetter,
357 &ScriptIdSetter,
358 attributes);
359 }
360
361
362 //
363 // Accessors::ScriptName
364 //
365
366
ScriptNameGetter(v8::Local<v8::String> name,const v8::PropertyCallbackInfo<v8::Value> & info)367 void Accessors::ScriptNameGetter(
368 v8::Local<v8::String> name,
369 const v8::PropertyCallbackInfo<v8::Value>& info) {
370 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
371 DisallowHeapAllocation no_allocation;
372 HandleScope scope(isolate);
373 Object* object = *Utils::OpenHandle(*info.This());
374 Object* source = Script::cast(JSValue::cast(object)->value())->name();
375 info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(source, isolate)));
376 }
377
378
ScriptNameSetter(v8::Local<v8::String> name,v8::Local<v8::Value> value,const v8::PropertyCallbackInfo<void> & info)379 void Accessors::ScriptNameSetter(
380 v8::Local<v8::String> name,
381 v8::Local<v8::Value> value,
382 const v8::PropertyCallbackInfo<void>& info) {
383 UNREACHABLE();
384 }
385
386
ScriptNameInfo(Isolate * isolate,PropertyAttributes attributes)387 Handle<AccessorInfo> Accessors::ScriptNameInfo(
388 Isolate* isolate, PropertyAttributes attributes) {
389 return MakeAccessor(isolate,
390 isolate->factory()->name_string(),
391 &ScriptNameGetter,
392 &ScriptNameSetter,
393 attributes);
394 }
395
396
397 //
398 // Accessors::ScriptSource
399 //
400
401
ScriptSourceGetter(v8::Local<v8::String> name,const v8::PropertyCallbackInfo<v8::Value> & info)402 void Accessors::ScriptSourceGetter(
403 v8::Local<v8::String> name,
404 const v8::PropertyCallbackInfo<v8::Value>& info) {
405 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
406 DisallowHeapAllocation no_allocation;
407 HandleScope scope(isolate);
408 Object* object = *Utils::OpenHandle(*info.This());
409 Object* source = Script::cast(JSValue::cast(object)->value())->source();
410 info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(source, isolate)));
411 }
412
413
ScriptSourceSetter(v8::Local<v8::String> name,v8::Local<v8::Value> value,const v8::PropertyCallbackInfo<void> & info)414 void Accessors::ScriptSourceSetter(
415 v8::Local<v8::String> name,
416 v8::Local<v8::Value> value,
417 const v8::PropertyCallbackInfo<void>& info) {
418 UNREACHABLE();
419 }
420
421
ScriptSourceInfo(Isolate * isolate,PropertyAttributes attributes)422 Handle<AccessorInfo> Accessors::ScriptSourceInfo(
423 Isolate* isolate, PropertyAttributes attributes) {
424 return MakeAccessor(isolate,
425 isolate->factory()->source_string(),
426 &ScriptSourceGetter,
427 &ScriptSourceSetter,
428 attributes);
429 }
430
431
432 //
433 // Accessors::ScriptLineOffset
434 //
435
436
ScriptLineOffsetGetter(v8::Local<v8::String> name,const v8::PropertyCallbackInfo<v8::Value> & info)437 void Accessors::ScriptLineOffsetGetter(
438 v8::Local<v8::String> name,
439 const v8::PropertyCallbackInfo<v8::Value>& info) {
440 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
441 DisallowHeapAllocation no_allocation;
442 HandleScope scope(isolate);
443 Object* object = *Utils::OpenHandle(*info.This());
444 Object* res = Script::cast(JSValue::cast(object)->value())->line_offset();
445 info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(res, isolate)));
446 }
447
448
ScriptLineOffsetSetter(v8::Local<v8::String> name,v8::Local<v8::Value> value,const v8::PropertyCallbackInfo<void> & info)449 void Accessors::ScriptLineOffsetSetter(
450 v8::Local<v8::String> name,
451 v8::Local<v8::Value> value,
452 const v8::PropertyCallbackInfo<void>& info) {
453 UNREACHABLE();
454 }
455
456
ScriptLineOffsetInfo(Isolate * isolate,PropertyAttributes attributes)457 Handle<AccessorInfo> Accessors::ScriptLineOffsetInfo(
458 Isolate* isolate, PropertyAttributes attributes) {
459 Handle<String> name(isolate->factory()->InternalizeOneByteString(
460 STATIC_ASCII_VECTOR("line_offset")));
461 return MakeAccessor(isolate,
462 name,
463 &ScriptLineOffsetGetter,
464 &ScriptLineOffsetSetter,
465 attributes);
466 }
467
468
469 //
470 // Accessors::ScriptType
471 //
472
473
ScriptTypeGetter(v8::Local<v8::String> name,const v8::PropertyCallbackInfo<v8::Value> & info)474 void Accessors::ScriptTypeGetter(
475 v8::Local<v8::String> name,
476 const v8::PropertyCallbackInfo<v8::Value>& info) {
477 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
478 DisallowHeapAllocation no_allocation;
479 HandleScope scope(isolate);
480 Object* object = *Utils::OpenHandle(*info.This());
481 Object* res = Script::cast(JSValue::cast(object)->value())->type();
482 info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(res, isolate)));
483 }
484
485
ScriptTypeSetter(v8::Local<v8::String> name,v8::Local<v8::Value> value,const v8::PropertyCallbackInfo<void> & info)486 void Accessors::ScriptTypeSetter(
487 v8::Local<v8::String> name,
488 v8::Local<v8::Value> value,
489 const v8::PropertyCallbackInfo<void>& info) {
490 UNREACHABLE();
491 }
492
493
ScriptTypeInfo(Isolate * isolate,PropertyAttributes attributes)494 Handle<AccessorInfo> Accessors::ScriptTypeInfo(
495 Isolate* isolate, PropertyAttributes attributes) {
496 Handle<String> name(isolate->factory()->InternalizeOneByteString(
497 STATIC_ASCII_VECTOR("type")));
498 return MakeAccessor(isolate,
499 name,
500 &ScriptTypeGetter,
501 &ScriptTypeSetter,
502 attributes);
503 }
504
505
506 //
507 // Accessors::ScriptCompilationType
508 //
509
510
ScriptCompilationTypeGetter(v8::Local<v8::String> name,const v8::PropertyCallbackInfo<v8::Value> & info)511 void Accessors::ScriptCompilationTypeGetter(
512 v8::Local<v8::String> name,
513 const v8::PropertyCallbackInfo<v8::Value>& info) {
514 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
515 DisallowHeapAllocation no_allocation;
516 HandleScope scope(isolate);
517 Object* object = *Utils::OpenHandle(*info.This());
518 Object* res = Smi::FromInt(
519 Script::cast(JSValue::cast(object)->value())->compilation_type());
520 info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(res, isolate)));
521 }
522
523
ScriptCompilationTypeSetter(v8::Local<v8::String> name,v8::Local<v8::Value> value,const v8::PropertyCallbackInfo<void> & info)524 void Accessors::ScriptCompilationTypeSetter(
525 v8::Local<v8::String> name,
526 v8::Local<v8::Value> value,
527 const v8::PropertyCallbackInfo<void>& info) {
528 UNREACHABLE();
529 }
530
531
ScriptCompilationTypeInfo(Isolate * isolate,PropertyAttributes attributes)532 Handle<AccessorInfo> Accessors::ScriptCompilationTypeInfo(
533 Isolate* isolate, PropertyAttributes attributes) {
534 Handle<String> name(isolate->factory()->InternalizeOneByteString(
535 STATIC_ASCII_VECTOR("compilation_type")));
536 return MakeAccessor(isolate,
537 name,
538 &ScriptCompilationTypeGetter,
539 &ScriptCompilationTypeSetter,
540 attributes);
541 }
542
543
544 //
545 // Accessors::ScriptGetLineEnds
546 //
547
548
ScriptLineEndsGetter(v8::Local<v8::String> name,const v8::PropertyCallbackInfo<v8::Value> & info)549 void Accessors::ScriptLineEndsGetter(
550 v8::Local<v8::String> name,
551 const v8::PropertyCallbackInfo<v8::Value>& info) {
552 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
553 HandleScope scope(isolate);
554 Handle<Object> object = Utils::OpenHandle(*info.This());
555 Handle<Script> script(
556 Script::cast(Handle<JSValue>::cast(object)->value()), isolate);
557 Script::InitLineEnds(script);
558 ASSERT(script->line_ends()->IsFixedArray());
559 Handle<FixedArray> line_ends(FixedArray::cast(script->line_ends()));
560 // We do not want anyone to modify this array from JS.
561 ASSERT(*line_ends == isolate->heap()->empty_fixed_array() ||
562 line_ends->map() == isolate->heap()->fixed_cow_array_map());
563 Handle<JSArray> js_array =
564 isolate->factory()->NewJSArrayWithElements(line_ends);
565 info.GetReturnValue().Set(Utils::ToLocal(js_array));
566 }
567
568
ScriptLineEndsSetter(v8::Local<v8::String> name,v8::Local<v8::Value> value,const v8::PropertyCallbackInfo<void> & info)569 void Accessors::ScriptLineEndsSetter(
570 v8::Local<v8::String> name,
571 v8::Local<v8::Value> value,
572 const v8::PropertyCallbackInfo<void>& info) {
573 UNREACHABLE();
574 }
575
576
ScriptLineEndsInfo(Isolate * isolate,PropertyAttributes attributes)577 Handle<AccessorInfo> Accessors::ScriptLineEndsInfo(
578 Isolate* isolate, PropertyAttributes attributes) {
579 Handle<String> name(isolate->factory()->InternalizeOneByteString(
580 STATIC_ASCII_VECTOR("line_ends")));
581 return MakeAccessor(isolate,
582 name,
583 &ScriptLineEndsGetter,
584 &ScriptLineEndsSetter,
585 attributes);
586 }
587
588
589 //
590 // Accessors::ScriptGetContextData
591 //
592
593
ScriptContextDataGetter(v8::Local<v8::String> name,const v8::PropertyCallbackInfo<v8::Value> & info)594 void Accessors::ScriptContextDataGetter(
595 v8::Local<v8::String> name,
596 const v8::PropertyCallbackInfo<v8::Value>& info) {
597 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
598 DisallowHeapAllocation no_allocation;
599 HandleScope scope(isolate);
600 Object* object = *Utils::OpenHandle(*info.This());
601 Object* res = Script::cast(JSValue::cast(object)->value())->context_data();
602 info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(res, isolate)));
603 }
604
605
ScriptContextDataSetter(v8::Local<v8::String> name,v8::Local<v8::Value> value,const v8::PropertyCallbackInfo<void> & info)606 void Accessors::ScriptContextDataSetter(
607 v8::Local<v8::String> name,
608 v8::Local<v8::Value> value,
609 const v8::PropertyCallbackInfo<void>& info) {
610 UNREACHABLE();
611 }
612
613
ScriptContextDataInfo(Isolate * isolate,PropertyAttributes attributes)614 Handle<AccessorInfo> Accessors::ScriptContextDataInfo(
615 Isolate* isolate, PropertyAttributes attributes) {
616 Handle<String> name(isolate->factory()->InternalizeOneByteString(
617 STATIC_ASCII_VECTOR("context_data")));
618 return MakeAccessor(isolate,
619 name,
620 &ScriptContextDataGetter,
621 &ScriptContextDataSetter,
622 attributes);
623 }
624
625
626 //
627 // Accessors::ScriptGetEvalFromScript
628 //
629
630
ScriptEvalFromScriptGetter(v8::Local<v8::String> name,const v8::PropertyCallbackInfo<v8::Value> & info)631 void Accessors::ScriptEvalFromScriptGetter(
632 v8::Local<v8::String> name,
633 const v8::PropertyCallbackInfo<v8::Value>& info) {
634 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
635 HandleScope scope(isolate);
636 Handle<Object> object = Utils::OpenHandle(*info.This());
637 Handle<Script> script(
638 Script::cast(Handle<JSValue>::cast(object)->value()), isolate);
639 Handle<Object> result = isolate->factory()->undefined_value();
640 if (!script->eval_from_shared()->IsUndefined()) {
641 Handle<SharedFunctionInfo> eval_from_shared(
642 SharedFunctionInfo::cast(script->eval_from_shared()));
643 if (eval_from_shared->script()->IsScript()) {
644 Handle<Script> eval_from_script(Script::cast(eval_from_shared->script()));
645 result = Script::GetWrapper(eval_from_script);
646 }
647 }
648
649 info.GetReturnValue().Set(Utils::ToLocal(result));
650 }
651
652
ScriptEvalFromScriptSetter(v8::Local<v8::String> name,v8::Local<v8::Value> value,const v8::PropertyCallbackInfo<void> & info)653 void Accessors::ScriptEvalFromScriptSetter(
654 v8::Local<v8::String> name,
655 v8::Local<v8::Value> value,
656 const v8::PropertyCallbackInfo<void>& info) {
657 UNREACHABLE();
658 }
659
660
ScriptEvalFromScriptInfo(Isolate * isolate,PropertyAttributes attributes)661 Handle<AccessorInfo> Accessors::ScriptEvalFromScriptInfo(
662 Isolate* isolate, PropertyAttributes attributes) {
663 Handle<String> name(isolate->factory()->InternalizeOneByteString(
664 STATIC_ASCII_VECTOR("eval_from_script")));
665 return MakeAccessor(isolate,
666 name,
667 &ScriptEvalFromScriptGetter,
668 &ScriptEvalFromScriptSetter,
669 attributes);
670 }
671
672
673 //
674 // Accessors::ScriptGetEvalFromScriptPosition
675 //
676
677
ScriptEvalFromScriptPositionGetter(v8::Local<v8::String> name,const v8::PropertyCallbackInfo<v8::Value> & info)678 void Accessors::ScriptEvalFromScriptPositionGetter(
679 v8::Local<v8::String> name,
680 const v8::PropertyCallbackInfo<v8::Value>& info) {
681 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
682 HandleScope scope(isolate);
683 Handle<Object> object = Utils::OpenHandle(*info.This());
684 Handle<Script> script(
685 Script::cast(Handle<JSValue>::cast(object)->value()), isolate);
686 Handle<Object> result = isolate->factory()->undefined_value();
687 if (script->compilation_type() == Script::COMPILATION_TYPE_EVAL) {
688 Handle<Code> code(SharedFunctionInfo::cast(
689 script->eval_from_shared())->code());
690 result = Handle<Object>(
691 Smi::FromInt(code->SourcePosition(code->instruction_start() +
692 script->eval_from_instructions_offset()->value())),
693 isolate);
694 }
695 info.GetReturnValue().Set(Utils::ToLocal(result));
696 }
697
698
ScriptEvalFromScriptPositionSetter(v8::Local<v8::String> name,v8::Local<v8::Value> value,const v8::PropertyCallbackInfo<void> & info)699 void Accessors::ScriptEvalFromScriptPositionSetter(
700 v8::Local<v8::String> name,
701 v8::Local<v8::Value> value,
702 const v8::PropertyCallbackInfo<void>& info) {
703 UNREACHABLE();
704 }
705
706
ScriptEvalFromScriptPositionInfo(Isolate * isolate,PropertyAttributes attributes)707 Handle<AccessorInfo> Accessors::ScriptEvalFromScriptPositionInfo(
708 Isolate* isolate, PropertyAttributes attributes) {
709 Handle<String> name(isolate->factory()->InternalizeOneByteString(
710 STATIC_ASCII_VECTOR("eval_from_script_position")));
711 return MakeAccessor(isolate,
712 name,
713 &ScriptEvalFromScriptPositionGetter,
714 &ScriptEvalFromScriptPositionSetter,
715 attributes);
716 }
717
718
719 //
720 // Accessors::ScriptGetEvalFromFunctionName
721 //
722
723
ScriptEvalFromFunctionNameGetter(v8::Local<v8::String> name,const v8::PropertyCallbackInfo<v8::Value> & info)724 void Accessors::ScriptEvalFromFunctionNameGetter(
725 v8::Local<v8::String> name,
726 const v8::PropertyCallbackInfo<v8::Value>& info) {
727 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
728 HandleScope scope(isolate);
729 Handle<Object> object = Utils::OpenHandle(*info.This());
730 Handle<Script> script(
731 Script::cast(Handle<JSValue>::cast(object)->value()), isolate);
732 Handle<Object> result;
733 Handle<SharedFunctionInfo> shared(
734 SharedFunctionInfo::cast(script->eval_from_shared()));
735 // Find the name of the function calling eval.
736 if (!shared->name()->IsUndefined()) {
737 result = Handle<Object>(shared->name(), isolate);
738 } else {
739 result = Handle<Object>(shared->inferred_name(), isolate);
740 }
741 info.GetReturnValue().Set(Utils::ToLocal(result));
742 }
743
744
ScriptEvalFromFunctionNameSetter(v8::Local<v8::String> name,v8::Local<v8::Value> value,const v8::PropertyCallbackInfo<void> & info)745 void Accessors::ScriptEvalFromFunctionNameSetter(
746 v8::Local<v8::String> name,
747 v8::Local<v8::Value> value,
748 const v8::PropertyCallbackInfo<void>& info) {
749 UNREACHABLE();
750 }
751
752
ScriptEvalFromFunctionNameInfo(Isolate * isolate,PropertyAttributes attributes)753 Handle<AccessorInfo> Accessors::ScriptEvalFromFunctionNameInfo(
754 Isolate* isolate, PropertyAttributes attributes) {
755 Handle<String> name(isolate->factory()->InternalizeOneByteString(
756 STATIC_ASCII_VECTOR("eval_from_function_name")));
757 return MakeAccessor(isolate,
758 name,
759 &ScriptEvalFromFunctionNameGetter,
760 &ScriptEvalFromFunctionNameSetter,
761 attributes);
762 }
763
764
765 //
766 // Accessors::FunctionPrototype
767 //
768
GetFunctionPrototype(Isolate * isolate,Handle<Object> receiver)769 static Handle<Object> GetFunctionPrototype(Isolate* isolate,
770 Handle<Object> receiver) {
771 Handle<JSFunction> function;
772 {
773 DisallowHeapAllocation no_allocation;
774 JSFunction* function_raw = FindInstanceOf<JSFunction>(isolate, *receiver);
775 if (function_raw == NULL) return isolate->factory()->undefined_value();
776 while (!function_raw->should_have_prototype()) {
777 function_raw = FindInstanceOf<JSFunction>(isolate,
778 function_raw->GetPrototype());
779 // There has to be one because we hit the getter.
780 ASSERT(function_raw != NULL);
781 }
782 function = Handle<JSFunction>(function_raw, isolate);
783 }
784
785 if (!function->has_prototype()) {
786 Handle<Object> proto = isolate->factory()->NewFunctionPrototype(function);
787 JSFunction::SetPrototype(function, proto);
788 }
789 return Handle<Object>(function->prototype(), isolate);
790 }
791
792
SetFunctionPrototype(Isolate * isolate,Handle<JSObject> receiver,Handle<Object> value)793 static Handle<Object> SetFunctionPrototype(Isolate* isolate,
794 Handle<JSObject> receiver,
795 Handle<Object> value) {
796 Handle<JSFunction> function;
797 {
798 DisallowHeapAllocation no_allocation;
799 JSFunction* function_raw = FindInstanceOf<JSFunction>(isolate, *receiver);
800 if (function_raw == NULL) return isolate->factory()->undefined_value();
801 function = Handle<JSFunction>(function_raw, isolate);
802 }
803
804 if (!function->should_have_prototype()) {
805 // Since we hit this accessor, object will have no prototype property.
806 MaybeHandle<Object> maybe_result =
807 JSObject::SetOwnPropertyIgnoreAttributes(
808 receiver, isolate->factory()->prototype_string(), value, NONE);
809 return maybe_result.ToHandleChecked();
810 }
811
812 Handle<Object> old_value;
813 bool is_observed = *function == *receiver && function->map()->is_observed();
814 if (is_observed) {
815 if (function->has_prototype())
816 old_value = handle(function->prototype(), isolate);
817 else
818 old_value = isolate->factory()->NewFunctionPrototype(function);
819 }
820
821 JSFunction::SetPrototype(function, value);
822 ASSERT(function->prototype() == *value);
823
824 if (is_observed && !old_value->SameValue(*value)) {
825 JSObject::EnqueueChangeRecord(
826 function, "update", isolate->factory()->prototype_string(), old_value);
827 }
828
829 return function;
830 }
831
832
FunctionGetPrototype(Handle<JSFunction> function)833 Handle<Object> Accessors::FunctionGetPrototype(Handle<JSFunction> function) {
834 return GetFunctionPrototype(function->GetIsolate(), function);
835 }
836
837
FunctionSetPrototype(Handle<JSFunction> function,Handle<Object> prototype)838 Handle<Object> Accessors::FunctionSetPrototype(Handle<JSFunction> function,
839 Handle<Object> prototype) {
840 ASSERT(function->should_have_prototype());
841 Isolate* isolate = function->GetIsolate();
842 return SetFunctionPrototype(isolate, function, prototype);
843 }
844
845
FunctionPrototypeGetter(v8::Local<v8::String> name,const v8::PropertyCallbackInfo<v8::Value> & info)846 void Accessors::FunctionPrototypeGetter(
847 v8::Local<v8::String> name,
848 const v8::PropertyCallbackInfo<v8::Value>& info) {
849 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
850 HandleScope scope(isolate);
851 Handle<Object> object = GetThisFrom(info);
852 Handle<Object> result = GetFunctionPrototype(isolate, object);
853 info.GetReturnValue().Set(Utils::ToLocal(result));
854 }
855
856
FunctionPrototypeSetter(v8::Local<v8::String> name,v8::Local<v8::Value> val,const v8::PropertyCallbackInfo<void> & info)857 void Accessors::FunctionPrototypeSetter(
858 v8::Local<v8::String> name,
859 v8::Local<v8::Value> val,
860 const v8::PropertyCallbackInfo<void>& info) {
861 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
862 HandleScope scope(isolate);
863 Handle<JSObject> object =
864 Handle<JSObject>::cast(Utils::OpenHandle(*info.This()));
865 Handle<Object> value = Utils::OpenHandle(*val);
866
867 SetFunctionPrototype(isolate, object, value);
868 }
869
870
FunctionPrototypeInfo(Isolate * isolate,PropertyAttributes attributes)871 Handle<AccessorInfo> Accessors::FunctionPrototypeInfo(
872 Isolate* isolate, PropertyAttributes attributes) {
873 return MakeAccessor(isolate,
874 isolate->factory()->prototype_string(),
875 &FunctionPrototypeGetter,
876 &FunctionPrototypeSetter,
877 attributes);
878 }
879
880
881 //
882 // Accessors::FunctionLength
883 //
884
885
FunctionLengthGetter(v8::Local<v8::String> name,const v8::PropertyCallbackInfo<v8::Value> & info)886 void Accessors::FunctionLengthGetter(
887 v8::Local<v8::String> name,
888 const v8::PropertyCallbackInfo<v8::Value>& info) {
889 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
890 HandleScope scope(isolate);
891 Handle<Object> object = GetThisFrom(info);
892 MaybeHandle<JSFunction> maybe_function;
893
894 {
895 DisallowHeapAllocation no_allocation;
896 JSFunction* function = FindInstanceOf<JSFunction>(isolate, *object);
897 if (function != NULL) maybe_function = Handle<JSFunction>(function);
898 }
899
900 int length = 0;
901 Handle<JSFunction> function;
902 if (maybe_function.ToHandle(&function)) {
903 if (function->shared()->is_compiled()) {
904 length = function->shared()->length();
905 } else {
906 // If the function isn't compiled yet, the length is not computed
907 // correctly yet. Compile it now and return the right length.
908 if (Compiler::EnsureCompiled(function, KEEP_EXCEPTION)) {
909 length = function->shared()->length();
910 }
911 if (isolate->has_pending_exception()) {
912 isolate->OptionalRescheduleException(false);
913 }
914 }
915 }
916 Handle<Object> result(Smi::FromInt(length), isolate);
917 info.GetReturnValue().Set(Utils::ToLocal(result));
918 }
919
920
FunctionLengthSetter(v8::Local<v8::String> name,v8::Local<v8::Value> val,const v8::PropertyCallbackInfo<void> & info)921 void Accessors::FunctionLengthSetter(
922 v8::Local<v8::String> name,
923 v8::Local<v8::Value> val,
924 const v8::PropertyCallbackInfo<void>& info) {
925 // Do nothing.
926 }
927
928
FunctionLengthInfo(Isolate * isolate,PropertyAttributes attributes)929 Handle<AccessorInfo> Accessors::FunctionLengthInfo(
930 Isolate* isolate, PropertyAttributes attributes) {
931 return MakeAccessor(isolate,
932 isolate->factory()->length_string(),
933 &FunctionLengthGetter,
934 &FunctionLengthSetter,
935 attributes);
936 }
937
938
939 //
940 // Accessors::FunctionName
941 //
942
943
FunctionNameGetter(v8::Local<v8::String> name,const v8::PropertyCallbackInfo<v8::Value> & info)944 void Accessors::FunctionNameGetter(
945 v8::Local<v8::String> name,
946 const v8::PropertyCallbackInfo<v8::Value>& info) {
947 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
948 HandleScope scope(isolate);
949 Handle<Object> object = GetThisFrom(info);
950 MaybeHandle<JSFunction> maybe_function;
951
952 {
953 DisallowHeapAllocation no_allocation;
954 JSFunction* function = FindInstanceOf<JSFunction>(isolate, *object);
955 if (function != NULL) maybe_function = Handle<JSFunction>(function);
956 }
957
958 Handle<JSFunction> function;
959 Handle<Object> result;
960 if (maybe_function.ToHandle(&function)) {
961 result = Handle<Object>(function->shared()->name(), isolate);
962 } else {
963 result = isolate->factory()->undefined_value();
964 }
965 info.GetReturnValue().Set(Utils::ToLocal(result));
966 }
967
968
FunctionNameSetter(v8::Local<v8::String> name,v8::Local<v8::Value> val,const v8::PropertyCallbackInfo<void> & info)969 void Accessors::FunctionNameSetter(
970 v8::Local<v8::String> name,
971 v8::Local<v8::Value> val,
972 const v8::PropertyCallbackInfo<void>& info) {
973 // Do nothing.
974 }
975
976
FunctionNameInfo(Isolate * isolate,PropertyAttributes attributes)977 Handle<AccessorInfo> Accessors::FunctionNameInfo(
978 Isolate* isolate, PropertyAttributes attributes) {
979 return MakeAccessor(isolate,
980 isolate->factory()->name_string(),
981 &FunctionNameGetter,
982 &FunctionNameSetter,
983 attributes);
984 }
985
986
987 //
988 // Accessors::FunctionArguments
989 //
990
991
ArgumentsForInlinedFunction(JavaScriptFrame * frame,Handle<JSFunction> inlined_function,int inlined_frame_index)992 static Handle<Object> ArgumentsForInlinedFunction(
993 JavaScriptFrame* frame,
994 Handle<JSFunction> inlined_function,
995 int inlined_frame_index) {
996 Isolate* isolate = inlined_function->GetIsolate();
997 Factory* factory = isolate->factory();
998 SlotRefValueBuilder slot_refs(
999 frame,
1000 inlined_frame_index,
1001 inlined_function->shared()->formal_parameter_count());
1002
1003 int args_count = slot_refs.args_length();
1004 Handle<JSObject> arguments =
1005 factory->NewArgumentsObject(inlined_function, args_count);
1006 Handle<FixedArray> array = factory->NewFixedArray(args_count);
1007 slot_refs.Prepare(isolate);
1008 for (int i = 0; i < args_count; ++i) {
1009 Handle<Object> value = slot_refs.GetNext(isolate, 0);
1010 array->set(i, *value);
1011 }
1012 slot_refs.Finish(isolate);
1013 arguments->set_elements(*array);
1014
1015 // Return the freshly allocated arguments object.
1016 return arguments;
1017 }
1018
1019
FindFunctionInFrame(JavaScriptFrame * frame,Handle<JSFunction> function)1020 static int FindFunctionInFrame(JavaScriptFrame* frame,
1021 Handle<JSFunction> function) {
1022 DisallowHeapAllocation no_allocation;
1023 List<JSFunction*> functions(2);
1024 frame->GetFunctions(&functions);
1025 for (int i = functions.length() - 1; i >= 0; i--) {
1026 if (functions[i] == *function) return i;
1027 }
1028 return -1;
1029 }
1030
1031
GetFunctionArguments(Isolate * isolate,Handle<JSFunction> function)1032 Handle<Object> GetFunctionArguments(Isolate* isolate,
1033 Handle<JSFunction> function) {
1034 if (function->shared()->native()) return isolate->factory()->null_value();
1035
1036 // Find the top invocation of the function by traversing frames.
1037 for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) {
1038 JavaScriptFrame* frame = it.frame();
1039 int function_index = FindFunctionInFrame(frame, function);
1040 if (function_index < 0) continue;
1041
1042 if (function_index > 0) {
1043 // The function in question was inlined. Inlined functions have the
1044 // correct number of arguments and no allocated arguments object, so
1045 // we can construct a fresh one by interpreting the function's
1046 // deoptimization input data.
1047 return ArgumentsForInlinedFunction(frame, function, function_index);
1048 }
1049
1050 if (!frame->is_optimized()) {
1051 // If there is an arguments variable in the stack, we return that.
1052 Handle<ScopeInfo> scope_info(function->shared()->scope_info());
1053 int index = scope_info->StackSlotIndex(
1054 isolate->heap()->arguments_string());
1055 if (index >= 0) {
1056 Handle<Object> arguments(frame->GetExpression(index), isolate);
1057 if (!arguments->IsArgumentsMarker()) return arguments;
1058 }
1059 }
1060
1061 // If there is no arguments variable in the stack or we have an
1062 // optimized frame, we find the frame that holds the actual arguments
1063 // passed to the function.
1064 it.AdvanceToArgumentsFrame();
1065 frame = it.frame();
1066
1067 // Get the number of arguments and construct an arguments object
1068 // mirror for the right frame.
1069 const int length = frame->ComputeParametersCount();
1070 Handle<JSObject> arguments = isolate->factory()->NewArgumentsObject(
1071 function, length);
1072 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
1073
1074 // Copy the parameters to the arguments object.
1075 ASSERT(array->length() == length);
1076 for (int i = 0; i < length; i++) array->set(i, frame->GetParameter(i));
1077 arguments->set_elements(*array);
1078
1079 // Return the freshly allocated arguments object.
1080 return arguments;
1081 }
1082
1083 // No frame corresponding to the given function found. Return null.
1084 return isolate->factory()->null_value();
1085 }
1086
1087
FunctionGetArguments(Handle<JSFunction> function)1088 Handle<Object> Accessors::FunctionGetArguments(Handle<JSFunction> function) {
1089 return GetFunctionArguments(function->GetIsolate(), function);
1090 }
1091
1092
FunctionArgumentsGetter(v8::Local<v8::String> name,const v8::PropertyCallbackInfo<v8::Value> & info)1093 void Accessors::FunctionArgumentsGetter(
1094 v8::Local<v8::String> name,
1095 const v8::PropertyCallbackInfo<v8::Value>& info) {
1096 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
1097 HandleScope scope(isolate);
1098 Handle<Object> object = GetThisFrom(info);
1099 MaybeHandle<JSFunction> maybe_function;
1100
1101 {
1102 DisallowHeapAllocation no_allocation;
1103 JSFunction* function = FindInstanceOf<JSFunction>(isolate, *object);
1104 if (function != NULL) maybe_function = Handle<JSFunction>(function);
1105 }
1106
1107 Handle<JSFunction> function;
1108 Handle<Object> result;
1109 if (maybe_function.ToHandle(&function)) {
1110 result = GetFunctionArguments(isolate, function);
1111 } else {
1112 result = isolate->factory()->undefined_value();
1113 }
1114 info.GetReturnValue().Set(Utils::ToLocal(result));
1115 }
1116
1117
FunctionArgumentsSetter(v8::Local<v8::String> name,v8::Local<v8::Value> val,const v8::PropertyCallbackInfo<void> & info)1118 void Accessors::FunctionArgumentsSetter(
1119 v8::Local<v8::String> name,
1120 v8::Local<v8::Value> val,
1121 const v8::PropertyCallbackInfo<void>& info) {
1122 // Do nothing.
1123 }
1124
1125
FunctionArgumentsInfo(Isolate * isolate,PropertyAttributes attributes)1126 Handle<AccessorInfo> Accessors::FunctionArgumentsInfo(
1127 Isolate* isolate, PropertyAttributes attributes) {
1128 return MakeAccessor(isolate,
1129 isolate->factory()->arguments_string(),
1130 &FunctionArgumentsGetter,
1131 &FunctionArgumentsSetter,
1132 attributes);
1133 }
1134
1135
1136 //
1137 // Accessors::FunctionCaller
1138 //
1139
1140
AllowAccessToFunction(Context * current_context,JSFunction * function)1141 static inline bool AllowAccessToFunction(Context* current_context,
1142 JSFunction* function) {
1143 return current_context->HasSameSecurityTokenAs(function->context());
1144 }
1145
1146
1147 class FrameFunctionIterator {
1148 public:
FrameFunctionIterator(Isolate * isolate,const DisallowHeapAllocation & promise)1149 FrameFunctionIterator(Isolate* isolate, const DisallowHeapAllocation& promise)
1150 : isolate_(isolate),
1151 frame_iterator_(isolate),
1152 functions_(2),
1153 index_(0) {
1154 GetFunctions();
1155 }
next()1156 JSFunction* next() {
1157 while (true) {
1158 if (functions_.length() == 0) return NULL;
1159 JSFunction* next_function = functions_[index_];
1160 index_--;
1161 if (index_ < 0) {
1162 GetFunctions();
1163 }
1164 // Skip functions from other origins.
1165 if (!AllowAccessToFunction(isolate_->context(), next_function)) continue;
1166 return next_function;
1167 }
1168 }
1169
1170 // Iterate through functions until the first occurence of 'function'.
1171 // Returns true if 'function' is found, and false if the iterator ends
1172 // without finding it.
Find(JSFunction * function)1173 bool Find(JSFunction* function) {
1174 JSFunction* next_function;
1175 do {
1176 next_function = next();
1177 if (next_function == function) return true;
1178 } while (next_function != NULL);
1179 return false;
1180 }
1181
1182 private:
GetFunctions()1183 void GetFunctions() {
1184 functions_.Rewind(0);
1185 if (frame_iterator_.done()) return;
1186 JavaScriptFrame* frame = frame_iterator_.frame();
1187 frame->GetFunctions(&functions_);
1188 ASSERT(functions_.length() > 0);
1189 frame_iterator_.Advance();
1190 index_ = functions_.length() - 1;
1191 }
1192 Isolate* isolate_;
1193 JavaScriptFrameIterator frame_iterator_;
1194 List<JSFunction*> functions_;
1195 int index_;
1196 };
1197
1198
FindCaller(Isolate * isolate,Handle<JSFunction> function)1199 MaybeHandle<JSFunction> FindCaller(Isolate* isolate,
1200 Handle<JSFunction> function) {
1201 DisallowHeapAllocation no_allocation;
1202 FrameFunctionIterator it(isolate, no_allocation);
1203 if (function->shared()->native()) {
1204 return MaybeHandle<JSFunction>();
1205 }
1206 // Find the function from the frames.
1207 if (!it.Find(*function)) {
1208 // No frame corresponding to the given function found. Return null.
1209 return MaybeHandle<JSFunction>();
1210 }
1211 // Find previously called non-toplevel function.
1212 JSFunction* caller;
1213 do {
1214 caller = it.next();
1215 if (caller == NULL) return MaybeHandle<JSFunction>();
1216 } while (caller->shared()->is_toplevel());
1217
1218 // If caller is a built-in function and caller's caller is also built-in,
1219 // use that instead.
1220 JSFunction* potential_caller = caller;
1221 while (potential_caller != NULL && potential_caller->IsBuiltin()) {
1222 caller = potential_caller;
1223 potential_caller = it.next();
1224 }
1225 if (!caller->shared()->native() && potential_caller != NULL) {
1226 caller = potential_caller;
1227 }
1228 // If caller is bound, return null. This is compatible with JSC, and
1229 // allows us to make bound functions use the strict function map
1230 // and its associated throwing caller and arguments.
1231 if (caller->shared()->bound()) {
1232 return MaybeHandle<JSFunction>();
1233 }
1234 // Censor if the caller is not a sloppy mode function.
1235 // Change from ES5, which used to throw, see:
1236 // https://bugs.ecmascript.org/show_bug.cgi?id=310
1237 if (caller->shared()->strict_mode() == STRICT) {
1238 return MaybeHandle<JSFunction>();
1239 }
1240 // Don't return caller from another security context.
1241 if (!AllowAccessToFunction(isolate->context(), caller)) {
1242 return MaybeHandle<JSFunction>();
1243 }
1244 return Handle<JSFunction>(caller);
1245 }
1246
1247
FunctionCallerGetter(v8::Local<v8::String> name,const v8::PropertyCallbackInfo<v8::Value> & info)1248 void Accessors::FunctionCallerGetter(
1249 v8::Local<v8::String> name,
1250 const v8::PropertyCallbackInfo<v8::Value>& info) {
1251 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
1252 HandleScope scope(isolate);
1253 Handle<Object> object = GetThisFrom(info);
1254 MaybeHandle<JSFunction> maybe_function;
1255 {
1256 DisallowHeapAllocation no_allocation;
1257 JSFunction* function = FindInstanceOf<JSFunction>(isolate, *object);
1258 if (function != NULL) maybe_function = Handle<JSFunction>(function);
1259 }
1260 Handle<JSFunction> function;
1261 Handle<Object> result;
1262 if (maybe_function.ToHandle(&function)) {
1263 MaybeHandle<JSFunction> maybe_caller;
1264 maybe_caller = FindCaller(isolate, function);
1265 Handle<JSFunction> caller;
1266 if (maybe_caller.ToHandle(&caller)) {
1267 result = caller;
1268 } else {
1269 result = isolate->factory()->null_value();
1270 }
1271 } else {
1272 result = isolate->factory()->undefined_value();
1273 }
1274 info.GetReturnValue().Set(Utils::ToLocal(result));
1275 }
1276
1277
FunctionCallerSetter(v8::Local<v8::String> name,v8::Local<v8::Value> val,const v8::PropertyCallbackInfo<void> & info)1278 void Accessors::FunctionCallerSetter(
1279 v8::Local<v8::String> name,
1280 v8::Local<v8::Value> val,
1281 const v8::PropertyCallbackInfo<void>& info) {
1282 // Do nothing.
1283 }
1284
1285
FunctionCallerInfo(Isolate * isolate,PropertyAttributes attributes)1286 Handle<AccessorInfo> Accessors::FunctionCallerInfo(
1287 Isolate* isolate, PropertyAttributes attributes) {
1288 return MakeAccessor(isolate,
1289 isolate->factory()->caller_string(),
1290 &FunctionCallerGetter,
1291 &FunctionCallerSetter,
1292 attributes);
1293 }
1294
1295
1296 //
1297 // Accessors::MakeModuleExport
1298 //
1299
ModuleGetExport(v8::Local<v8::String> property,const v8::PropertyCallbackInfo<v8::Value> & info)1300 static void ModuleGetExport(
1301 v8::Local<v8::String> property,
1302 const v8::PropertyCallbackInfo<v8::Value>& info) {
1303 JSModule* instance = JSModule::cast(*v8::Utils::OpenHandle(*info.Holder()));
1304 Context* context = Context::cast(instance->context());
1305 ASSERT(context->IsModuleContext());
1306 int slot = info.Data()->Int32Value();
1307 Object* value = context->get(slot);
1308 Isolate* isolate = instance->GetIsolate();
1309 if (value->IsTheHole()) {
1310 Handle<String> name = v8::Utils::OpenHandle(*property);
1311 isolate->ScheduleThrow(
1312 *isolate->factory()->NewReferenceError("not_defined",
1313 HandleVector(&name, 1)));
1314 return;
1315 }
1316 info.GetReturnValue().Set(v8::Utils::ToLocal(Handle<Object>(value, isolate)));
1317 }
1318
1319
ModuleSetExport(v8::Local<v8::String> property,v8::Local<v8::Value> value,const v8::PropertyCallbackInfo<v8::Value> & info)1320 static void ModuleSetExport(
1321 v8::Local<v8::String> property,
1322 v8::Local<v8::Value> value,
1323 const v8::PropertyCallbackInfo<v8::Value>& info) {
1324 JSModule* instance = JSModule::cast(*v8::Utils::OpenHandle(*info.Holder()));
1325 Context* context = Context::cast(instance->context());
1326 ASSERT(context->IsModuleContext());
1327 int slot = info.Data()->Int32Value();
1328 Object* old_value = context->get(slot);
1329 if (old_value->IsTheHole()) {
1330 Handle<String> name = v8::Utils::OpenHandle(*property);
1331 Isolate* isolate = instance->GetIsolate();
1332 isolate->ScheduleThrow(
1333 *isolate->factory()->NewReferenceError("not_defined",
1334 HandleVector(&name, 1)));
1335 return;
1336 }
1337 context->set(slot, *v8::Utils::OpenHandle(*value));
1338 }
1339
1340
MakeModuleExport(Handle<String> name,int index,PropertyAttributes attributes)1341 Handle<AccessorInfo> Accessors::MakeModuleExport(
1342 Handle<String> name,
1343 int index,
1344 PropertyAttributes attributes) {
1345 Isolate* isolate = name->GetIsolate();
1346 Factory* factory = isolate->factory();
1347 Handle<ExecutableAccessorInfo> info = factory->NewExecutableAccessorInfo();
1348 info->set_property_attributes(attributes);
1349 info->set_all_can_read(true);
1350 info->set_all_can_write(true);
1351 info->set_name(*name);
1352 info->set_data(Smi::FromInt(index));
1353 Handle<Object> getter = v8::FromCData(isolate, &ModuleGetExport);
1354 Handle<Object> setter = v8::FromCData(isolate, &ModuleSetExport);
1355 info->set_getter(*getter);
1356 if (!(attributes & ReadOnly)) info->set_setter(*setter);
1357 return info;
1358 }
1359
1360
1361 } } // namespace v8::internal
1362