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