Upstream version 6.35.121.0
[platform/framework/web/crosswalk.git] / src / v8 / src / accessors.cc
1 // Copyright 2012 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 #include "accessors.h"
30
31 #include "compiler.h"
32 #include "contexts.h"
33 #include "deoptimizer.h"
34 #include "execution.h"
35 #include "factory.h"
36 #include "frames-inl.h"
37 #include "isolate.h"
38 #include "list-inl.h"
39 #include "property-details.h"
40
41 namespace v8 {
42 namespace internal {
43
44
45 template <class C>
46 static C* FindInstanceOf(Isolate* isolate, Object* obj) {
47   for (Object* cur = obj; !cur->IsNull(); cur = cur->GetPrototype(isolate)) {
48     if (Is<C>(cur)) return C::cast(cur);
49   }
50   return NULL;
51 }
52
53
54 // Entry point that never should be called.
55 MaybeObject* Accessors::IllegalSetter(Isolate* isolate,
56                                       JSObject*,
57                                       Object*,
58                                       void*) {
59   UNREACHABLE();
60   return NULL;
61 }
62
63
64 Object* Accessors::IllegalGetAccessor(Isolate* isolate,
65                                       Object* object,
66                                       void*) {
67   UNREACHABLE();
68   return object;
69 }
70
71
72 MaybeObject* Accessors::ReadOnlySetAccessor(Isolate* isolate,
73                                             JSObject*,
74                                             Object* value,
75                                             void*) {
76   // According to ECMA-262, section 8.6.2.2, page 28, setting
77   // read-only properties must be silently ignored.
78   return value;
79 }
80
81
82 static V8_INLINE bool CheckForName(Handle<String> name,
83                                    String* property_name,
84                                    int offset,
85                                    int* object_offset) {
86   if (name->Equals(property_name)) {
87     *object_offset = offset;
88     return true;
89   }
90   return false;
91 }
92
93
94 // Returns true for properties that are accessors to object fields.
95 // If true, *object_offset contains offset of object field.
96 template <class T>
97 bool Accessors::IsJSObjectFieldAccessor(typename T::TypeHandle type,
98                                         Handle<String> name,
99                                         int* object_offset) {
100   Isolate* isolate = name->GetIsolate();
101
102   if (type->Is(T::String())) {
103     return CheckForName(name, isolate->heap()->length_string(),
104                         String::kLengthOffset, object_offset);
105   }
106
107   if (!type->IsClass()) return false;
108   Handle<Map> map = type->AsClass();
109
110   switch (map->instance_type()) {
111     case JS_ARRAY_TYPE:
112       return
113         CheckForName(name, isolate->heap()->length_string(),
114                      JSArray::kLengthOffset, object_offset);
115     case JS_TYPED_ARRAY_TYPE:
116       return
117         CheckForName(name, isolate->heap()->length_string(),
118                      JSTypedArray::kLengthOffset, object_offset) ||
119         CheckForName(name, isolate->heap()->byte_length_string(),
120                      JSTypedArray::kByteLengthOffset, object_offset) ||
121         CheckForName(name, isolate->heap()->byte_offset_string(),
122                      JSTypedArray::kByteOffsetOffset, object_offset);
123     case JS_ARRAY_BUFFER_TYPE:
124       return
125         CheckForName(name, isolate->heap()->byte_length_string(),
126                      JSArrayBuffer::kByteLengthOffset, object_offset);
127     case JS_DATA_VIEW_TYPE:
128       return
129         CheckForName(name, isolate->heap()->byte_length_string(),
130                      JSDataView::kByteLengthOffset, object_offset) ||
131         CheckForName(name, isolate->heap()->byte_offset_string(),
132                      JSDataView::kByteOffsetOffset, object_offset);
133     default:
134       return false;
135   }
136 }
137
138
139 template
140 bool Accessors::IsJSObjectFieldAccessor<Type>(Type* type,
141                                               Handle<String> name,
142                                               int* object_offset);
143
144
145 template
146 bool Accessors::IsJSObjectFieldAccessor<HeapType>(Handle<HeapType> type,
147                                                   Handle<String> name,
148                                                   int* object_offset);
149
150
151 //
152 // Accessors::ArrayLength
153 //
154
155
156 MaybeObject* Accessors::ArrayGetLength(Isolate* isolate,
157                                        Object* object,
158                                        void*) {
159   // Traverse the prototype chain until we reach an array.
160   JSArray* holder = FindInstanceOf<JSArray>(isolate, object);
161   return holder == NULL ? Smi::FromInt(0) : holder->length();
162 }
163
164
165 // The helper function will 'flatten' Number objects.
166 Handle<Object> Accessors::FlattenNumber(Isolate* isolate,
167                                         Handle<Object> value) {
168   if (value->IsNumber() || !value->IsJSValue()) return value;
169   Handle<JSValue> wrapper = Handle<JSValue>::cast(value);
170   ASSERT(wrapper->GetIsolate()->context()->native_context()->number_function()->
171       has_initial_map());
172   if (wrapper->map() ==
173       isolate->context()->native_context()->number_function()->initial_map()) {
174     return handle(wrapper->value(), isolate);
175   }
176
177   return value;
178 }
179
180
181 MaybeObject* Accessors::ArraySetLength(Isolate* isolate,
182                                        JSObject* object_raw,
183                                        Object* value_raw,
184                                        void*) {
185   HandleScope scope(isolate);
186   Handle<JSObject> object(object_raw, isolate);
187   Handle<Object> value(value_raw, isolate);
188
189   // This means one of the object's prototypes is a JSArray and the
190   // object does not have a 'length' property.  Calling SetProperty
191   // causes an infinite loop.
192   if (!object->IsJSArray()) {
193     Handle<Object> result = JSObject::SetLocalPropertyIgnoreAttributes(object,
194         isolate->factory()->length_string(), value, NONE);
195     RETURN_IF_EMPTY_HANDLE(isolate, result);
196     return *result;
197   }
198
199   value = FlattenNumber(isolate, value);
200
201   Handle<JSArray> array_handle = Handle<JSArray>::cast(object);
202
203   bool has_exception;
204   Handle<Object> uint32_v =
205       Execution::ToUint32(isolate, value, &has_exception);
206   if (has_exception) return Failure::Exception();
207   Handle<Object> number_v =
208       Execution::ToNumber(isolate, value, &has_exception);
209   if (has_exception) return Failure::Exception();
210
211   if (uint32_v->Number() == number_v->Number()) {
212     Handle<Object> result = JSArray::SetElementsLength(array_handle, uint32_v);
213     RETURN_IF_EMPTY_HANDLE(isolate, result);
214     return *result;
215   }
216   return isolate->Throw(
217       *isolate->factory()->NewRangeError("invalid_array_length",
218                                          HandleVector<Object>(NULL, 0)));
219 }
220
221
222 const AccessorDescriptor Accessors::ArrayLength = {
223   ArrayGetLength,
224   ArraySetLength,
225   0
226 };
227
228
229 //
230 // Accessors::StringLength
231 //
232
233
234 MaybeObject* Accessors::StringGetLength(Isolate* isolate,
235                                         Object* object,
236                                         void*) {
237   Object* value = object;
238   if (object->IsJSValue()) value = JSValue::cast(object)->value();
239   if (value->IsString()) return Smi::FromInt(String::cast(value)->length());
240   // If object is not a string we return 0 to be compatible with WebKit.
241   // Note: Firefox returns the length of ToString(object).
242   return Smi::FromInt(0);
243 }
244
245
246 const AccessorDescriptor Accessors::StringLength = {
247   StringGetLength,
248   IllegalSetter,
249   0
250 };
251
252
253 //
254 // Accessors::ScriptSource
255 //
256
257
258 MaybeObject* Accessors::ScriptGetSource(Isolate* isolate,
259                                         Object* object,
260                                         void*) {
261   Object* script = JSValue::cast(object)->value();
262   return Script::cast(script)->source();
263 }
264
265
266 const AccessorDescriptor Accessors::ScriptSource = {
267   ScriptGetSource,
268   IllegalSetter,
269   0
270 };
271
272
273 //
274 // Accessors::ScriptName
275 //
276
277
278 MaybeObject* Accessors::ScriptGetName(Isolate* isolate,
279                                       Object* object,
280                                       void*) {
281   Object* script = JSValue::cast(object)->value();
282   return Script::cast(script)->name();
283 }
284
285
286 const AccessorDescriptor Accessors::ScriptName = {
287   ScriptGetName,
288   IllegalSetter,
289   0
290 };
291
292
293 //
294 // Accessors::ScriptId
295 //
296
297
298 MaybeObject* Accessors::ScriptGetId(Isolate* isolate, Object* object, void*) {
299   Object* script = JSValue::cast(object)->value();
300   return Script::cast(script)->id();
301 }
302
303
304 const AccessorDescriptor Accessors::ScriptId = {
305   ScriptGetId,
306   IllegalSetter,
307   0
308 };
309
310
311 //
312 // Accessors::ScriptLineOffset
313 //
314
315
316 MaybeObject* Accessors::ScriptGetLineOffset(Isolate* isolate,
317                                             Object* object,
318                                             void*) {
319   Object* script = JSValue::cast(object)->value();
320   return Script::cast(script)->line_offset();
321 }
322
323
324 const AccessorDescriptor Accessors::ScriptLineOffset = {
325   ScriptGetLineOffset,
326   IllegalSetter,
327   0
328 };
329
330
331 //
332 // Accessors::ScriptColumnOffset
333 //
334
335
336 MaybeObject* Accessors::ScriptGetColumnOffset(Isolate* isolate,
337                                               Object* object,
338                                               void*) {
339   Object* script = JSValue::cast(object)->value();
340   return Script::cast(script)->column_offset();
341 }
342
343
344 const AccessorDescriptor Accessors::ScriptColumnOffset = {
345   ScriptGetColumnOffset,
346   IllegalSetter,
347   0
348 };
349
350
351 //
352 // Accessors::ScriptType
353 //
354
355
356 MaybeObject* Accessors::ScriptGetType(Isolate* isolate,
357                                       Object* object,
358                                       void*) {
359   Object* script = JSValue::cast(object)->value();
360   return Script::cast(script)->type();
361 }
362
363
364 const AccessorDescriptor Accessors::ScriptType = {
365   ScriptGetType,
366   IllegalSetter,
367   0
368 };
369
370
371 //
372 // Accessors::ScriptCompilationType
373 //
374
375
376 MaybeObject* Accessors::ScriptGetCompilationType(Isolate* isolate,
377                                                  Object* object,
378                                                  void*) {
379   Object* script = JSValue::cast(object)->value();
380   return Smi::FromInt(Script::cast(script)->compilation_type());
381 }
382
383
384 const AccessorDescriptor Accessors::ScriptCompilationType = {
385   ScriptGetCompilationType,
386   IllegalSetter,
387   0
388 };
389
390
391 //
392 // Accessors::ScriptGetLineEnds
393 //
394
395
396 MaybeObject* Accessors::ScriptGetLineEnds(Isolate* isolate,
397                                           Object* object,
398                                           void*) {
399   JSValue* wrapper = JSValue::cast(object);
400   HandleScope scope(isolate);
401   Handle<Script> script(Script::cast(wrapper->value()), isolate);
402   InitScriptLineEnds(script);
403   ASSERT(script->line_ends()->IsFixedArray());
404   Handle<FixedArray> line_ends(FixedArray::cast(script->line_ends()));
405   // We do not want anyone to modify this array from JS.
406   ASSERT(*line_ends == isolate->heap()->empty_fixed_array() ||
407          line_ends->map() == isolate->heap()->fixed_cow_array_map());
408   Handle<JSArray> js_array =
409       isolate->factory()->NewJSArrayWithElements(line_ends);
410   return *js_array;
411 }
412
413
414 const AccessorDescriptor Accessors::ScriptLineEnds = {
415   ScriptGetLineEnds,
416   IllegalSetter,
417   0
418 };
419
420
421 //
422 // Accessors::ScriptGetContextData
423 //
424
425
426 MaybeObject* Accessors::ScriptGetContextData(Isolate* isolate,
427                                              Object* object,
428                                              void*) {
429   Object* script = JSValue::cast(object)->value();
430   return Script::cast(script)->context_data();
431 }
432
433
434 const AccessorDescriptor Accessors::ScriptContextData = {
435   ScriptGetContextData,
436   IllegalSetter,
437   0
438 };
439
440
441 //
442 // Accessors::ScriptGetEvalFromScript
443 //
444
445
446 MaybeObject* Accessors::ScriptGetEvalFromScript(Isolate* isolate,
447                                                 Object* object,
448                                                 void*) {
449   Object* script = JSValue::cast(object)->value();
450   if (!Script::cast(script)->eval_from_shared()->IsUndefined()) {
451     Handle<SharedFunctionInfo> eval_from_shared(
452         SharedFunctionInfo::cast(Script::cast(script)->eval_from_shared()));
453
454     if (eval_from_shared->script()->IsScript()) {
455       Handle<Script> eval_from_script(Script::cast(eval_from_shared->script()));
456       return *GetScriptWrapper(eval_from_script);
457     }
458   }
459   return isolate->heap()->undefined_value();
460 }
461
462
463 const AccessorDescriptor Accessors::ScriptEvalFromScript = {
464   ScriptGetEvalFromScript,
465   IllegalSetter,
466   0
467 };
468
469
470 //
471 // Accessors::ScriptGetEvalFromScriptPosition
472 //
473
474
475 MaybeObject* Accessors::ScriptGetEvalFromScriptPosition(Isolate* isolate,
476                                                         Object* object,
477                                                         void*) {
478   Script* raw_script = Script::cast(JSValue::cast(object)->value());
479   HandleScope scope(isolate);
480   Handle<Script> script(raw_script);
481
482   // If this is not a script compiled through eval there is no eval position.
483   if (script->compilation_type() != Script::COMPILATION_TYPE_EVAL) {
484     return script->GetHeap()->undefined_value();
485   }
486
487   // Get the function from where eval was called and find the source position
488   // from the instruction offset.
489   Handle<Code> code(SharedFunctionInfo::cast(
490       script->eval_from_shared())->code());
491   return Smi::FromInt(code->SourcePosition(code->instruction_start() +
492                       script->eval_from_instructions_offset()->value()));
493 }
494
495
496 const AccessorDescriptor Accessors::ScriptEvalFromScriptPosition = {
497   ScriptGetEvalFromScriptPosition,
498   IllegalSetter,
499   0
500 };
501
502
503 //
504 // Accessors::ScriptGetEvalFromFunctionName
505 //
506
507
508 MaybeObject* Accessors::ScriptGetEvalFromFunctionName(Isolate* isolate,
509                                                       Object* object,
510                                                       void*) {
511   Object* script = JSValue::cast(object)->value();
512   Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(
513       Script::cast(script)->eval_from_shared()));
514
515
516   // Find the name of the function calling eval.
517   if (!shared->name()->IsUndefined()) {
518     return shared->name();
519   } else {
520     return shared->inferred_name();
521   }
522 }
523
524
525 const AccessorDescriptor Accessors::ScriptEvalFromFunctionName = {
526   ScriptGetEvalFromFunctionName,
527   IllegalSetter,
528   0
529 };
530
531
532 //
533 // Accessors::FunctionPrototype
534 //
535
536
537 Handle<Object> Accessors::FunctionGetPrototype(Handle<JSFunction> function) {
538   CALL_HEAP_FUNCTION(function->GetIsolate(),
539                      Accessors::FunctionGetPrototype(function->GetIsolate(),
540                                                      *function,
541                                                      NULL),
542                      Object);
543 }
544
545
546 Handle<Object> Accessors::FunctionSetPrototype(Handle<JSFunction> function,
547                                                Handle<Object> prototype) {
548   ASSERT(function->should_have_prototype());
549   CALL_HEAP_FUNCTION(function->GetIsolate(),
550                      Accessors::FunctionSetPrototype(function->GetIsolate(),
551                                                      *function,
552                                                      *prototype,
553                                                      NULL),
554                      Object);
555 }
556
557
558 MaybeObject* Accessors::FunctionGetPrototype(Isolate* isolate,
559                                              Object* object,
560                                              void*) {
561   JSFunction* function_raw = FindInstanceOf<JSFunction>(isolate, object);
562   if (function_raw == NULL) return isolate->heap()->undefined_value();
563   while (!function_raw->should_have_prototype()) {
564     function_raw = FindInstanceOf<JSFunction>(isolate,
565                                               function_raw->GetPrototype());
566     // There has to be one because we hit the getter.
567     ASSERT(function_raw != NULL);
568   }
569
570   if (!function_raw->has_prototype()) {
571     HandleScope scope(isolate);
572     Handle<JSFunction> function(function_raw);
573     Handle<Object> proto = isolate->factory()->NewFunctionPrototype(function);
574     JSFunction::SetPrototype(function, proto);
575     function_raw = *function;
576   }
577   return function_raw->prototype();
578 }
579
580
581 MaybeObject* Accessors::FunctionSetPrototype(Isolate* isolate,
582                                              JSObject* object_raw,
583                                              Object* value_raw,
584                                              void*) {
585   JSFunction* function_raw = FindInstanceOf<JSFunction>(isolate, object_raw);
586   if (function_raw == NULL) return isolate->heap()->undefined_value();
587
588   HandleScope scope(isolate);
589   Handle<JSFunction> function(function_raw, isolate);
590   Handle<JSObject> object(object_raw, isolate);
591   Handle<Object> value(value_raw, isolate);
592   if (!function->should_have_prototype()) {
593     // Since we hit this accessor, object will have no prototype property.
594     Handle<Object> result = JSObject::SetLocalPropertyIgnoreAttributes(object,
595         isolate->factory()->prototype_string(), value, NONE);
596     RETURN_IF_EMPTY_HANDLE(isolate, result);
597     return *result;
598   }
599
600   Handle<Object> old_value;
601   bool is_observed = *function == *object && function->map()->is_observed();
602   if (is_observed) {
603     if (function->has_prototype())
604       old_value = handle(function->prototype(), isolate);
605     else
606       old_value = isolate->factory()->NewFunctionPrototype(function);
607   }
608
609   JSFunction::SetPrototype(function, value);
610   ASSERT(function->prototype() == *value);
611
612   if (is_observed && !old_value->SameValue(*value)) {
613     JSObject::EnqueueChangeRecord(
614         function, "update", isolate->factory()->prototype_string(), old_value);
615   }
616
617   return *function;
618 }
619
620
621 const AccessorDescriptor Accessors::FunctionPrototype = {
622   FunctionGetPrototype,
623   FunctionSetPrototype,
624   0
625 };
626
627
628 //
629 // Accessors::FunctionLength
630 //
631
632
633 MaybeObject* Accessors::FunctionGetLength(Isolate* isolate,
634                                           Object* object,
635                                           void*) {
636   JSFunction* function = FindInstanceOf<JSFunction>(isolate, object);
637   if (function == NULL) return Smi::FromInt(0);
638   // Check if already compiled.
639   if (function->shared()->is_compiled()) {
640     return Smi::FromInt(function->shared()->length());
641   }
642   // If the function isn't compiled yet, the length is not computed correctly
643   // yet. Compile it now and return the right length.
644   HandleScope scope(isolate);
645   Handle<JSFunction> function_handle(function);
646   if (Compiler::EnsureCompiled(function_handle, KEEP_EXCEPTION)) {
647     return Smi::FromInt(function_handle->shared()->length());
648   }
649   return Failure::Exception();
650 }
651
652
653 const AccessorDescriptor Accessors::FunctionLength = {
654   FunctionGetLength,
655   ReadOnlySetAccessor,
656   0
657 };
658
659
660 //
661 // Accessors::FunctionName
662 //
663
664
665 MaybeObject* Accessors::FunctionGetName(Isolate* isolate,
666                                         Object* object,
667                                         void*) {
668   JSFunction* holder = FindInstanceOf<JSFunction>(isolate, object);
669   return holder == NULL
670       ? isolate->heap()->undefined_value()
671       : holder->shared()->name();
672 }
673
674
675 const AccessorDescriptor Accessors::FunctionName = {
676   FunctionGetName,
677   ReadOnlySetAccessor,
678   0
679 };
680
681
682 //
683 // Accessors::FunctionArguments
684 //
685
686
687 Handle<Object> Accessors::FunctionGetArguments(Handle<JSFunction> function) {
688   CALL_HEAP_FUNCTION(function->GetIsolate(),
689                      Accessors::FunctionGetArguments(function->GetIsolate(),
690                                                      *function,
691                                                      NULL),
692                      Object);
693 }
694
695
696 static MaybeObject* ConstructArgumentsObjectForInlinedFunction(
697     JavaScriptFrame* frame,
698     Handle<JSFunction> inlined_function,
699     int inlined_frame_index) {
700   Isolate* isolate = inlined_function->GetIsolate();
701   Factory* factory = isolate->factory();
702   SlotRefValueBuilder slot_refs(
703       frame,
704       inlined_frame_index,
705       inlined_function->shared()->formal_parameter_count());
706
707   int args_count = slot_refs.args_length();
708   Handle<JSObject> arguments =
709       factory->NewArgumentsObject(inlined_function, args_count);
710   Handle<FixedArray> array = factory->NewFixedArray(args_count);
711   slot_refs.Prepare(isolate);
712   for (int i = 0; i < args_count; ++i) {
713     Handle<Object> value = slot_refs.GetNext(isolate, 0);
714     array->set(i, *value);
715   }
716   slot_refs.Finish(isolate);
717   arguments->set_elements(*array);
718
719   // Return the freshly allocated arguments object.
720   return *arguments;
721 }
722
723
724 MaybeObject* Accessors::FunctionGetArguments(Isolate* isolate,
725                                              Object* object,
726                                              void*) {
727   HandleScope scope(isolate);
728   JSFunction* holder = FindInstanceOf<JSFunction>(isolate, object);
729   if (holder == NULL) return isolate->heap()->undefined_value();
730   Handle<JSFunction> function(holder, isolate);
731
732   if (function->shared()->native()) return isolate->heap()->null_value();
733   // Find the top invocation of the function by traversing frames.
734   List<JSFunction*> functions(2);
735   for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) {
736     JavaScriptFrame* frame = it.frame();
737     frame->GetFunctions(&functions);
738     for (int i = functions.length() - 1; i >= 0; i--) {
739       // Skip all frames that aren't invocations of the given function.
740       if (functions[i] != *function) continue;
741
742       if (i > 0) {
743         // The function in question was inlined.  Inlined functions have the
744         // correct number of arguments and no allocated arguments object, so
745         // we can construct a fresh one by interpreting the function's
746         // deoptimization input data.
747         return ConstructArgumentsObjectForInlinedFunction(frame, function, i);
748       }
749
750       if (!frame->is_optimized()) {
751         // If there is an arguments variable in the stack, we return that.
752         Handle<ScopeInfo> scope_info(function->shared()->scope_info());
753         int index = scope_info->StackSlotIndex(
754             isolate->heap()->arguments_string());
755         if (index >= 0) {
756           Handle<Object> arguments(frame->GetExpression(index), isolate);
757           if (!arguments->IsArgumentsMarker()) return *arguments;
758         }
759       }
760
761       // If there is no arguments variable in the stack or we have an
762       // optimized frame, we find the frame that holds the actual arguments
763       // passed to the function.
764       it.AdvanceToArgumentsFrame();
765       frame = it.frame();
766
767       // Get the number of arguments and construct an arguments object
768       // mirror for the right frame.
769       const int length = frame->ComputeParametersCount();
770       Handle<JSObject> arguments = isolate->factory()->NewArgumentsObject(
771           function, length);
772       Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
773
774       // Copy the parameters to the arguments object.
775       ASSERT(array->length() == length);
776       for (int i = 0; i < length; i++) array->set(i, frame->GetParameter(i));
777       arguments->set_elements(*array);
778
779       // Return the freshly allocated arguments object.
780       return *arguments;
781     }
782     functions.Rewind(0);
783   }
784
785   // No frame corresponding to the given function found. Return null.
786   return isolate->heap()->null_value();
787 }
788
789
790 const AccessorDescriptor Accessors::FunctionArguments = {
791   FunctionGetArguments,
792   ReadOnlySetAccessor,
793   0
794 };
795
796
797 //
798 // Accessors::FunctionCaller
799 //
800
801
802 class FrameFunctionIterator {
803  public:
804   FrameFunctionIterator(Isolate* isolate, const DisallowHeapAllocation& promise)
805       : frame_iterator_(isolate),
806         functions_(2),
807         index_(0) {
808     GetFunctions();
809   }
810   JSFunction* next() {
811     if (functions_.length() == 0) return NULL;
812     JSFunction* next_function = functions_[index_];
813     index_--;
814     if (index_ < 0) {
815       GetFunctions();
816     }
817     return next_function;
818   }
819
820   // Iterate through functions until the first occurence of 'function'.
821   // Returns true if 'function' is found, and false if the iterator ends
822   // without finding it.
823   bool Find(JSFunction* function) {
824     JSFunction* next_function;
825     do {
826       next_function = next();
827       if (next_function == function) return true;
828     } while (next_function != NULL);
829     return false;
830   }
831
832  private:
833   void GetFunctions() {
834     functions_.Rewind(0);
835     if (frame_iterator_.done()) return;
836     JavaScriptFrame* frame = frame_iterator_.frame();
837     frame->GetFunctions(&functions_);
838     ASSERT(functions_.length() > 0);
839     frame_iterator_.Advance();
840     index_ = functions_.length() - 1;
841   }
842   JavaScriptFrameIterator frame_iterator_;
843   List<JSFunction*> functions_;
844   int index_;
845 };
846
847
848 MaybeObject* Accessors::FunctionGetCaller(Isolate* isolate,
849                                           Object* object,
850                                           void*) {
851   HandleScope scope(isolate);
852   DisallowHeapAllocation no_allocation;
853   JSFunction* holder = FindInstanceOf<JSFunction>(isolate, object);
854   if (holder == NULL) return isolate->heap()->undefined_value();
855   if (holder->shared()->native()) return isolate->heap()->null_value();
856   Handle<JSFunction> function(holder, isolate);
857
858   FrameFunctionIterator it(isolate, no_allocation);
859
860   // Find the function from the frames.
861   if (!it.Find(*function)) {
862     // No frame corresponding to the given function found. Return null.
863     return isolate->heap()->null_value();
864   }
865
866   // Find previously called non-toplevel function.
867   JSFunction* caller;
868   do {
869     caller = it.next();
870     if (caller == NULL) return isolate->heap()->null_value();
871   } while (caller->shared()->is_toplevel());
872
873   // If caller is a built-in function and caller's caller is also built-in,
874   // use that instead.
875   JSFunction* potential_caller = caller;
876   while (potential_caller != NULL && potential_caller->IsBuiltin()) {
877     caller = potential_caller;
878     potential_caller = it.next();
879   }
880   if (!caller->shared()->native() && potential_caller != NULL) {
881     caller = potential_caller;
882   }
883   // If caller is bound, return null. This is compatible with JSC, and
884   // allows us to make bound functions use the strict function map
885   // and its associated throwing caller and arguments.
886   if (caller->shared()->bound()) {
887     return isolate->heap()->null_value();
888   }
889   // Censor if the caller is not a sloppy mode function.
890   // Change from ES5, which used to throw, see:
891   // https://bugs.ecmascript.org/show_bug.cgi?id=310
892   if (caller->shared()->strict_mode() == STRICT) {
893     return isolate->heap()->null_value();
894   }
895
896   return caller;
897 }
898
899
900 const AccessorDescriptor Accessors::FunctionCaller = {
901   FunctionGetCaller,
902   ReadOnlySetAccessor,
903   0
904 };
905
906
907 //
908 // Accessors::MakeModuleExport
909 //
910
911 static void ModuleGetExport(
912     v8::Local<v8::String> property,
913     const v8::PropertyCallbackInfo<v8::Value>& info) {
914   JSModule* instance = JSModule::cast(*v8::Utils::OpenHandle(*info.Holder()));
915   Context* context = Context::cast(instance->context());
916   ASSERT(context->IsModuleContext());
917   int slot = info.Data()->Int32Value();
918   Object* value = context->get(slot);
919   Isolate* isolate = instance->GetIsolate();
920   if (value->IsTheHole()) {
921     Handle<String> name = v8::Utils::OpenHandle(*property);
922     isolate->ScheduleThrow(
923         *isolate->factory()->NewReferenceError("not_defined",
924                                                HandleVector(&name, 1)));
925     return;
926   }
927   info.GetReturnValue().Set(v8::Utils::ToLocal(Handle<Object>(value, isolate)));
928 }
929
930
931 static void ModuleSetExport(
932     v8::Local<v8::String> property,
933     v8::Local<v8::Value> value,
934     const v8::PropertyCallbackInfo<v8::Value>& info) {
935   JSModule* instance = JSModule::cast(*v8::Utils::OpenHandle(*info.Holder()));
936   Context* context = Context::cast(instance->context());
937   ASSERT(context->IsModuleContext());
938   int slot = info.Data()->Int32Value();
939   Object* old_value = context->get(slot);
940   if (old_value->IsTheHole()) {
941     Handle<String> name = v8::Utils::OpenHandle(*property);
942     Isolate* isolate = instance->GetIsolate();
943     isolate->ScheduleThrow(
944         *isolate->factory()->NewReferenceError("not_defined",
945                                                HandleVector(&name, 1)));
946     return;
947   }
948   context->set(slot, *v8::Utils::OpenHandle(*value));
949 }
950
951
952 Handle<AccessorInfo> Accessors::MakeModuleExport(
953     Handle<String> name,
954     int index,
955     PropertyAttributes attributes) {
956   Isolate* isolate = name->GetIsolate();
957   Factory* factory = isolate->factory();
958   Handle<ExecutableAccessorInfo> info = factory->NewExecutableAccessorInfo();
959   info->set_property_attributes(attributes);
960   info->set_all_can_read(true);
961   info->set_all_can_write(true);
962   info->set_name(*name);
963   info->set_data(Smi::FromInt(index));
964   Handle<Object> getter = v8::FromCData(isolate, &ModuleGetExport);
965   Handle<Object> setter = v8::FromCData(isolate, &ModuleSetExport);
966   info->set_getter(*getter);
967   if (!(attributes & ReadOnly)) info->set_setter(*setter);
968   return info;
969 }
970
971
972 } }  // namespace v8::internal