1 // Copyright 2006-2008 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28 #include "v8.h"
29
30 #include "accessors.h"
31 #include "ast.h"
32 #include "deoptimizer.h"
33 #include "execution.h"
34 #include "factory.h"
35 #include "safepoint-table.h"
36 #include "scopeinfo.h"
37
38 namespace v8 {
39 namespace internal {
40
41
42 template <class C>
FindInPrototypeChain(Object * obj,bool * found_it)43 static C* FindInPrototypeChain(Object* obj, bool* found_it) {
44 ASSERT(!*found_it);
45 Heap* heap = HEAP;
46 while (!Is<C>(obj)) {
47 if (obj == heap->null_value()) return NULL;
48 obj = obj->GetPrototype();
49 }
50 *found_it = true;
51 return C::cast(obj);
52 }
53
54
55 // Entry point that never should be called.
IllegalSetter(JSObject *,Object *,void *)56 MaybeObject* Accessors::IllegalSetter(JSObject*, Object*, void*) {
57 UNREACHABLE();
58 return NULL;
59 }
60
61
IllegalGetAccessor(Object * object,void *)62 Object* Accessors::IllegalGetAccessor(Object* object, void*) {
63 UNREACHABLE();
64 return object;
65 }
66
67
ReadOnlySetAccessor(JSObject *,Object * value,void *)68 MaybeObject* Accessors::ReadOnlySetAccessor(JSObject*, Object* value, void*) {
69 // According to ECMA-262, section 8.6.2.2, page 28, setting
70 // read-only properties must be silently ignored.
71 return value;
72 }
73
74
75 //
76 // Accessors::ArrayLength
77 //
78
79
ArrayGetLength(Object * object,void *)80 MaybeObject* Accessors::ArrayGetLength(Object* object, void*) {
81 // Traverse the prototype chain until we reach an array.
82 bool found_it = false;
83 JSArray* holder = FindInPrototypeChain<JSArray>(object, &found_it);
84 if (!found_it) return Smi::FromInt(0);
85 return holder->length();
86 }
87
88
89 // The helper function will 'flatten' Number objects.
FlattenNumber(Object * value)90 Object* Accessors::FlattenNumber(Object* value) {
91 if (value->IsNumber() || !value->IsJSValue()) return value;
92 JSValue* wrapper = JSValue::cast(value);
93 ASSERT(Isolate::Current()->context()->global_context()->number_function()->
94 has_initial_map());
95 Map* number_map = Isolate::Current()->context()->global_context()->
96 number_function()->initial_map();
97 if (wrapper->map() == number_map) return wrapper->value();
98 return value;
99 }
100
101
ArraySetLength(JSObject * object,Object * value,void *)102 MaybeObject* Accessors::ArraySetLength(JSObject* object, Object* value, void*) {
103 Isolate* isolate = object->GetIsolate();
104
105 // This means one of the object's prototypes is a JSArray and the
106 // object does not have a 'length' property. Calling SetProperty
107 // causes an infinite loop.
108 if (!object->IsJSArray()) {
109 return object->SetLocalPropertyIgnoreAttributes(
110 isolate->heap()->length_symbol(), value, NONE);
111 }
112
113 value = FlattenNumber(value);
114
115 // Need to call methods that may trigger GC.
116 HandleScope scope(isolate);
117
118 // Protect raw pointers.
119 Handle<JSObject> object_handle(object, isolate);
120 Handle<Object> value_handle(value, isolate);
121
122 bool has_exception;
123 Handle<Object> uint32_v = Execution::ToUint32(value_handle, &has_exception);
124 if (has_exception) return Failure::Exception();
125 Handle<Object> number_v = Execution::ToNumber(value_handle, &has_exception);
126 if (has_exception) return Failure::Exception();
127
128 if (uint32_v->Number() == number_v->Number()) {
129 return Handle<JSArray>::cast(object_handle)->SetElementsLength(*uint32_v);
130 }
131 return isolate->Throw(
132 *isolate->factory()->NewRangeError("invalid_array_length",
133 HandleVector<Object>(NULL, 0)));
134 }
135
136
137 const AccessorDescriptor Accessors::ArrayLength = {
138 ArrayGetLength,
139 ArraySetLength,
140 0
141 };
142
143
144 //
145 // Accessors::StringLength
146 //
147
148
StringGetLength(Object * object,void *)149 MaybeObject* Accessors::StringGetLength(Object* object, void*) {
150 Object* value = object;
151 if (object->IsJSValue()) value = JSValue::cast(object)->value();
152 if (value->IsString()) return Smi::FromInt(String::cast(value)->length());
153 // If object is not a string we return 0 to be compatible with WebKit.
154 // Note: Firefox returns the length of ToString(object).
155 return Smi::FromInt(0);
156 }
157
158
159 const AccessorDescriptor Accessors::StringLength = {
160 StringGetLength,
161 IllegalSetter,
162 0
163 };
164
165
166 //
167 // Accessors::ScriptSource
168 //
169
170
ScriptGetSource(Object * object,void *)171 MaybeObject* Accessors::ScriptGetSource(Object* object, void*) {
172 Object* script = JSValue::cast(object)->value();
173 return Script::cast(script)->source();
174 }
175
176
177 const AccessorDescriptor Accessors::ScriptSource = {
178 ScriptGetSource,
179 IllegalSetter,
180 0
181 };
182
183
184 //
185 // Accessors::ScriptName
186 //
187
188
ScriptGetName(Object * object,void *)189 MaybeObject* Accessors::ScriptGetName(Object* object, void*) {
190 Object* script = JSValue::cast(object)->value();
191 return Script::cast(script)->name();
192 }
193
194
195 const AccessorDescriptor Accessors::ScriptName = {
196 ScriptGetName,
197 IllegalSetter,
198 0
199 };
200
201
202 //
203 // Accessors::ScriptId
204 //
205
206
ScriptGetId(Object * object,void *)207 MaybeObject* Accessors::ScriptGetId(Object* object, void*) {
208 Object* script = JSValue::cast(object)->value();
209 return Script::cast(script)->id();
210 }
211
212
213 const AccessorDescriptor Accessors::ScriptId = {
214 ScriptGetId,
215 IllegalSetter,
216 0
217 };
218
219
220 //
221 // Accessors::ScriptLineOffset
222 //
223
224
ScriptGetLineOffset(Object * object,void *)225 MaybeObject* Accessors::ScriptGetLineOffset(Object* object, void*) {
226 Object* script = JSValue::cast(object)->value();
227 return Script::cast(script)->line_offset();
228 }
229
230
231 const AccessorDescriptor Accessors::ScriptLineOffset = {
232 ScriptGetLineOffset,
233 IllegalSetter,
234 0
235 };
236
237
238 //
239 // Accessors::ScriptColumnOffset
240 //
241
242
ScriptGetColumnOffset(Object * object,void *)243 MaybeObject* Accessors::ScriptGetColumnOffset(Object* object, void*) {
244 Object* script = JSValue::cast(object)->value();
245 return Script::cast(script)->column_offset();
246 }
247
248
249 const AccessorDescriptor Accessors::ScriptColumnOffset = {
250 ScriptGetColumnOffset,
251 IllegalSetter,
252 0
253 };
254
255
256 //
257 // Accessors::ScriptData
258 //
259
260
ScriptGetData(Object * object,void *)261 MaybeObject* Accessors::ScriptGetData(Object* object, void*) {
262 Object* script = JSValue::cast(object)->value();
263 return Script::cast(script)->data();
264 }
265
266
267 const AccessorDescriptor Accessors::ScriptData = {
268 ScriptGetData,
269 IllegalSetter,
270 0
271 };
272
273
274 //
275 // Accessors::ScriptType
276 //
277
278
ScriptGetType(Object * object,void *)279 MaybeObject* Accessors::ScriptGetType(Object* object, void*) {
280 Object* script = JSValue::cast(object)->value();
281 return Script::cast(script)->type();
282 }
283
284
285 const AccessorDescriptor Accessors::ScriptType = {
286 ScriptGetType,
287 IllegalSetter,
288 0
289 };
290
291
292 //
293 // Accessors::ScriptCompilationType
294 //
295
296
ScriptGetCompilationType(Object * object,void *)297 MaybeObject* Accessors::ScriptGetCompilationType(Object* object, void*) {
298 Object* script = JSValue::cast(object)->value();
299 return Script::cast(script)->compilation_type();
300 }
301
302
303 const AccessorDescriptor Accessors::ScriptCompilationType = {
304 ScriptGetCompilationType,
305 IllegalSetter,
306 0
307 };
308
309
310 //
311 // Accessors::ScriptGetLineEnds
312 //
313
314
ScriptGetLineEnds(Object * object,void *)315 MaybeObject* Accessors::ScriptGetLineEnds(Object* object, void*) {
316 JSValue* wrapper = JSValue::cast(object);
317 Isolate* isolate = wrapper->GetIsolate();
318 HandleScope scope(isolate);
319 Handle<Script> script(Script::cast(wrapper->value()), isolate);
320 InitScriptLineEnds(script);
321 ASSERT(script->line_ends()->IsFixedArray());
322 Handle<FixedArray> line_ends(FixedArray::cast(script->line_ends()));
323 // We do not want anyone to modify this array from JS.
324 ASSERT(*line_ends == isolate->heap()->empty_fixed_array() ||
325 line_ends->map() == isolate->heap()->fixed_cow_array_map());
326 Handle<JSArray> js_array =
327 isolate->factory()->NewJSArrayWithElements(line_ends);
328 return *js_array;
329 }
330
331
332 const AccessorDescriptor Accessors::ScriptLineEnds = {
333 ScriptGetLineEnds,
334 IllegalSetter,
335 0
336 };
337
338
339 //
340 // Accessors::ScriptGetContextData
341 //
342
343
ScriptGetContextData(Object * object,void *)344 MaybeObject* Accessors::ScriptGetContextData(Object* object, void*) {
345 Object* script = JSValue::cast(object)->value();
346 return Script::cast(script)->context_data();
347 }
348
349
350 const AccessorDescriptor Accessors::ScriptContextData = {
351 ScriptGetContextData,
352 IllegalSetter,
353 0
354 };
355
356
357 //
358 // Accessors::ScriptGetEvalFromScript
359 //
360
361
ScriptGetEvalFromScript(Object * object,void *)362 MaybeObject* Accessors::ScriptGetEvalFromScript(Object* object, void*) {
363 Object* script = JSValue::cast(object)->value();
364 if (!Script::cast(script)->eval_from_shared()->IsUndefined()) {
365 Handle<SharedFunctionInfo> eval_from_shared(
366 SharedFunctionInfo::cast(Script::cast(script)->eval_from_shared()));
367
368 if (eval_from_shared->script()->IsScript()) {
369 Handle<Script> eval_from_script(Script::cast(eval_from_shared->script()));
370 return *GetScriptWrapper(eval_from_script);
371 }
372 }
373 return HEAP->undefined_value();
374 }
375
376
377 const AccessorDescriptor Accessors::ScriptEvalFromScript = {
378 ScriptGetEvalFromScript,
379 IllegalSetter,
380 0
381 };
382
383
384 //
385 // Accessors::ScriptGetEvalFromScriptPosition
386 //
387
388
ScriptGetEvalFromScriptPosition(Object * object,void *)389 MaybeObject* Accessors::ScriptGetEvalFromScriptPosition(Object* object, void*) {
390 HandleScope scope;
391 Handle<Script> script(Script::cast(JSValue::cast(object)->value()));
392
393 // If this is not a script compiled through eval there is no eval position.
394 int compilation_type = Smi::cast(script->compilation_type())->value();
395 if (compilation_type != Script::COMPILATION_TYPE_EVAL) {
396 return HEAP->undefined_value();
397 }
398
399 // Get the function from where eval was called and find the source position
400 // from the instruction offset.
401 Handle<Code> code(SharedFunctionInfo::cast(
402 script->eval_from_shared())->code());
403 return Smi::FromInt(code->SourcePosition(code->instruction_start() +
404 script->eval_from_instructions_offset()->value()));
405 }
406
407
408 const AccessorDescriptor Accessors::ScriptEvalFromScriptPosition = {
409 ScriptGetEvalFromScriptPosition,
410 IllegalSetter,
411 0
412 };
413
414
415 //
416 // Accessors::ScriptGetEvalFromFunctionName
417 //
418
419
ScriptGetEvalFromFunctionName(Object * object,void *)420 MaybeObject* Accessors::ScriptGetEvalFromFunctionName(Object* object, void*) {
421 Object* script = JSValue::cast(object)->value();
422 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(
423 Script::cast(script)->eval_from_shared()));
424
425
426 // Find the name of the function calling eval.
427 if (!shared->name()->IsUndefined()) {
428 return shared->name();
429 } else {
430 return shared->inferred_name();
431 }
432 }
433
434
435 const AccessorDescriptor Accessors::ScriptEvalFromFunctionName = {
436 ScriptGetEvalFromFunctionName,
437 IllegalSetter,
438 0
439 };
440
441
442 //
443 // Accessors::FunctionPrototype
444 //
445
446
FunctionGetPrototype(Object * object,void *)447 MaybeObject* Accessors::FunctionGetPrototype(Object* object, void*) {
448 Heap* heap = Isolate::Current()->heap();
449 bool found_it = false;
450 JSFunction* function = FindInPrototypeChain<JSFunction>(object, &found_it);
451 if (!found_it) return heap->undefined_value();
452 while (!function->should_have_prototype()) {
453 found_it = false;
454 function = FindInPrototypeChain<JSFunction>(object->GetPrototype(),
455 &found_it);
456 // There has to be one because we hit the getter.
457 ASSERT(found_it);
458 }
459
460 if (!function->has_prototype()) {
461 Object* prototype;
462 { MaybeObject* maybe_prototype = heap->AllocateFunctionPrototype(function);
463 if (!maybe_prototype->ToObject(&prototype)) return maybe_prototype;
464 }
465 Object* result;
466 { MaybeObject* maybe_result = function->SetPrototype(prototype);
467 if (!maybe_result->ToObject(&result)) return maybe_result;
468 }
469 }
470 return function->prototype();
471 }
472
473
FunctionSetPrototype(JSObject * object,Object * value,void *)474 MaybeObject* Accessors::FunctionSetPrototype(JSObject* object,
475 Object* value,
476 void*) {
477 Heap* heap = object->GetHeap();
478 bool found_it = false;
479 JSFunction* function = FindInPrototypeChain<JSFunction>(object, &found_it);
480 if (!found_it) return heap->undefined_value();
481 if (!function->should_have_prototype()) {
482 // Since we hit this accessor, object will have no prototype property.
483 return object->SetLocalPropertyIgnoreAttributes(heap->prototype_symbol(),
484 value,
485 NONE);
486 }
487
488 if (function->has_initial_map()) {
489 // If the function has allocated the initial map
490 // replace it with a copy containing the new prototype.
491 Object* new_map;
492 { MaybeObject* maybe_new_map =
493 function->initial_map()->CopyDropTransitions();
494 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
495 }
496 function->set_initial_map(Map::cast(new_map));
497 }
498 Object* prototype;
499 { MaybeObject* maybe_prototype = function->SetPrototype(value);
500 if (!maybe_prototype->ToObject(&prototype)) return maybe_prototype;
501 }
502 ASSERT(function->prototype() == value);
503 return function;
504 }
505
506
507 const AccessorDescriptor Accessors::FunctionPrototype = {
508 FunctionGetPrototype,
509 FunctionSetPrototype,
510 0
511 };
512
513
514 //
515 // Accessors::FunctionLength
516 //
517
518
FunctionGetLength(Object * object,void *)519 MaybeObject* Accessors::FunctionGetLength(Object* object, void*) {
520 bool found_it = false;
521 JSFunction* function = FindInPrototypeChain<JSFunction>(object, &found_it);
522 if (!found_it) return Smi::FromInt(0);
523 // Check if already compiled.
524 if (!function->shared()->is_compiled()) {
525 // If the function isn't compiled yet, the length is not computed
526 // correctly yet. Compile it now and return the right length.
527 HandleScope scope;
528 Handle<JSFunction> handle(function);
529 if (!CompileLazy(handle, KEEP_EXCEPTION)) return Failure::Exception();
530 return Smi::FromInt(handle->shared()->length());
531 } else {
532 return Smi::FromInt(function->shared()->length());
533 }
534 }
535
536
537 const AccessorDescriptor Accessors::FunctionLength = {
538 FunctionGetLength,
539 ReadOnlySetAccessor,
540 0
541 };
542
543
544 //
545 // Accessors::FunctionName
546 //
547
548
FunctionGetName(Object * object,void *)549 MaybeObject* Accessors::FunctionGetName(Object* object, void*) {
550 bool found_it = false;
551 JSFunction* holder = FindInPrototypeChain<JSFunction>(object, &found_it);
552 if (!found_it) return HEAP->undefined_value();
553 return holder->shared()->name();
554 }
555
556
557 const AccessorDescriptor Accessors::FunctionName = {
558 FunctionGetName,
559 ReadOnlySetAccessor,
560 0
561 };
562
563
564 //
565 // Accessors::FunctionArguments
566 //
567
568
ConstructArgumentsObjectForInlinedFunction(JavaScriptFrame * frame,Handle<JSFunction> inlined_function,int inlined_frame_index)569 static MaybeObject* ConstructArgumentsObjectForInlinedFunction(
570 JavaScriptFrame* frame,
571 Handle<JSFunction> inlined_function,
572 int inlined_frame_index) {
573 Factory* factory = Isolate::Current()->factory();
574 int args_count = inlined_function->shared()->formal_parameter_count();
575 ScopedVector<SlotRef> args_slots(args_count);
576 SlotRef::ComputeSlotMappingForArguments(frame,
577 inlined_frame_index,
578 &args_slots);
579 Handle<JSObject> arguments =
580 factory->NewArgumentsObject(inlined_function, args_count);
581 Handle<FixedArray> array = factory->NewFixedArray(args_count);
582 for (int i = 0; i < args_count; ++i) {
583 Handle<Object> value = args_slots[i].GetValue();
584 array->set(i, *value);
585 }
586 arguments->set_elements(*array);
587
588 // Return the freshly allocated arguments object.
589 return *arguments;
590 }
591
592
FunctionGetArguments(Object * object,void *)593 MaybeObject* Accessors::FunctionGetArguments(Object* object, void*) {
594 Isolate* isolate = Isolate::Current();
595 HandleScope scope(isolate);
596 bool found_it = false;
597 JSFunction* holder = FindInPrototypeChain<JSFunction>(object, &found_it);
598 if (!found_it) return isolate->heap()->undefined_value();
599 Handle<JSFunction> function(holder, isolate);
600
601 // Find the top invocation of the function by traversing frames.
602 List<JSFunction*> functions(2);
603 for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) {
604 JavaScriptFrame* frame = it.frame();
605 frame->GetFunctions(&functions);
606 for (int i = functions.length() - 1; i >= 0; i--) {
607 // Skip all frames that aren't invocations of the given function.
608 if (functions[i] != *function) continue;
609
610 if (i > 0) {
611 // The function in question was inlined. Inlined functions have the
612 // correct number of arguments and no allocated arguments object, so
613 // we can construct a fresh one by interpreting the function's
614 // deoptimization input data.
615 return ConstructArgumentsObjectForInlinedFunction(frame, function, i);
616 }
617
618 if (!frame->is_optimized()) {
619 // If there is an arguments variable in the stack, we return that.
620 Handle<SerializedScopeInfo> info(function->shared()->scope_info());
621 int index = info->StackSlotIndex(isolate->heap()->arguments_symbol());
622 if (index >= 0) {
623 Handle<Object> arguments(frame->GetExpression(index), isolate);
624 if (!arguments->IsArgumentsMarker()) return *arguments;
625 }
626 }
627
628 // If there is no arguments variable in the stack or we have an
629 // optimized frame, we find the frame that holds the actual arguments
630 // passed to the function.
631 it.AdvanceToArgumentsFrame();
632 frame = it.frame();
633
634 // Get the number of arguments and construct an arguments object
635 // mirror for the right frame.
636 const int length = frame->ComputeParametersCount();
637 Handle<JSObject> arguments = isolate->factory()->NewArgumentsObject(
638 function, length);
639 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
640
641 // Copy the parameters to the arguments object.
642 ASSERT(array->length() == length);
643 for (int i = 0; i < length; i++) array->set(i, frame->GetParameter(i));
644 arguments->set_elements(*array);
645
646 // Return the freshly allocated arguments object.
647 return *arguments;
648 }
649 functions.Rewind(0);
650 }
651
652 // No frame corresponding to the given function found. Return null.
653 return isolate->heap()->null_value();
654 }
655
656
657 const AccessorDescriptor Accessors::FunctionArguments = {
658 FunctionGetArguments,
659 ReadOnlySetAccessor,
660 0
661 };
662
663
664 //
665 // Accessors::FunctionCaller
666 //
667
668
CheckNonStrictCallerOrThrow(Isolate * isolate,JSFunction * caller)669 static MaybeObject* CheckNonStrictCallerOrThrow(
670 Isolate* isolate,
671 JSFunction* caller) {
672 DisableAssertNoAllocation enable_allocation;
673 if (caller->shared()->strict_mode()) {
674 return isolate->Throw(
675 *isolate->factory()->NewTypeError("strict_caller",
676 HandleVector<Object>(NULL, 0)));
677 }
678 return caller;
679 }
680
681
FunctionGetCaller(Object * object,void *)682 MaybeObject* Accessors::FunctionGetCaller(Object* object, void*) {
683 Isolate* isolate = Isolate::Current();
684 HandleScope scope(isolate);
685 AssertNoAllocation no_alloc;
686 bool found_it = false;
687 JSFunction* holder = FindInPrototypeChain<JSFunction>(object, &found_it);
688 if (!found_it) return isolate->heap()->undefined_value();
689 Handle<JSFunction> function(holder, isolate);
690
691 List<JSFunction*> functions(2);
692 for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) {
693 JavaScriptFrame* frame = it.frame();
694 frame->GetFunctions(&functions);
695 for (int i = functions.length() - 1; i >= 0; i--) {
696 if (functions[i] == *function) {
697 // Once we have found the frame, we need to go to the caller
698 // frame. This may require skipping through a number of top-level
699 // frames, e.g. frames for scripts not functions.
700 if (i > 0) {
701 ASSERT(!functions[i - 1]->shared()->is_toplevel());
702 return CheckNonStrictCallerOrThrow(isolate, functions[i - 1]);
703 } else {
704 for (it.Advance(); !it.done(); it.Advance()) {
705 frame = it.frame();
706 functions.Rewind(0);
707 frame->GetFunctions(&functions);
708 if (!functions.last()->shared()->is_toplevel()) {
709 return CheckNonStrictCallerOrThrow(isolate, functions.last());
710 }
711 ASSERT(functions.length() == 1);
712 }
713 if (it.done()) return isolate->heap()->null_value();
714 break;
715 }
716 }
717 }
718 functions.Rewind(0);
719 }
720
721 // No frame corresponding to the given function found. Return null.
722 return isolate->heap()->null_value();
723 }
724
725
726 const AccessorDescriptor Accessors::FunctionCaller = {
727 FunctionGetCaller,
728 ReadOnlySetAccessor,
729 0
730 };
731
732
733 //
734 // Accessors::ObjectPrototype
735 //
736
737
ObjectGetPrototype(Object * receiver,void *)738 MaybeObject* Accessors::ObjectGetPrototype(Object* receiver, void*) {
739 Object* current = receiver->GetPrototype();
740 while (current->IsJSObject() &&
741 JSObject::cast(current)->map()->is_hidden_prototype()) {
742 current = current->GetPrototype();
743 }
744 return current;
745 }
746
747
ObjectSetPrototype(JSObject * receiver,Object * value,void *)748 MaybeObject* Accessors::ObjectSetPrototype(JSObject* receiver,
749 Object* value,
750 void*) {
751 const bool skip_hidden_prototypes = true;
752 // To be consistent with other Set functions, return the value.
753 return receiver->SetPrototype(value, skip_hidden_prototypes);
754 }
755
756
757 const AccessorDescriptor Accessors::ObjectPrototype = {
758 ObjectGetPrototype,
759 ObjectSetPrototype,
760 0
761 };
762
763 } } // namespace v8::internal
764