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