Home | History | Annotate | Download | only in src
      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 
     40 namespace v8 {
     41 namespace internal {
     42 
     43 
     44 template <class C>
     45 static 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.
     54 MaybeObject* Accessors::IllegalSetter(Isolate* isolate,
     55                                       JSObject*,
     56                                       Object*,
     57                                       void*) {
     58   UNREACHABLE();
     59   return NULL;
     60 }
     61 
     62 
     63 Object* Accessors::IllegalGetAccessor(Isolate* isolate,
     64                                       Object* object,
     65                                       void*) {
     66   UNREACHABLE();
     67   return object;
     68 }
     69 
     70 
     71 MaybeObject* 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 
     81 static 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 
     93 bool 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 
    141 MaybeObject* 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.
    151 Handle<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 
    166 MaybeObject* 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 
    205 const AccessorDescriptor Accessors::ArrayLength = {
    206   ArrayGetLength,
    207   ArraySetLength,
    208   0
    209 };
    210 
    211 
    212 //
    213 // Accessors::StringLength
    214 //
    215 
    216 
    217 MaybeObject* 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 
    229 const AccessorDescriptor Accessors::StringLength = {
    230   StringGetLength,
    231   IllegalSetter,
    232   0
    233 };
    234 
    235 
    236 //
    237 // Accessors::ScriptSource
    238 //
    239 
    240 
    241 MaybeObject* 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 
    249 const AccessorDescriptor Accessors::ScriptSource = {
    250   ScriptGetSource,
    251   IllegalSetter,
    252   0
    253 };
    254 
    255 
    256 //
    257 // Accessors::ScriptName
    258 //
    259 
    260 
    261 MaybeObject* 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 
    269 const AccessorDescriptor Accessors::ScriptName = {
    270   ScriptGetName,
    271   IllegalSetter,
    272   0
    273 };
    274 
    275 
    276 //
    277 // Accessors::ScriptId
    278 //
    279 
    280 
    281 MaybeObject* Accessors::ScriptGetId(Isolate* isolate, Object* object, void*) {
    282   Object* script = JSValue::cast(object)->value();
    283   return Script::cast(script)->id();
    284 }
    285 
    286 
    287 const AccessorDescriptor Accessors::ScriptId = {
    288   ScriptGetId,
    289   IllegalSetter,
    290   0
    291 };
    292 
    293 
    294 //
    295 // Accessors::ScriptLineOffset
    296 //
    297 
    298 
    299 MaybeObject* 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 
    307 const AccessorDescriptor Accessors::ScriptLineOffset = {
    308   ScriptGetLineOffset,
    309   IllegalSetter,
    310   0
    311 };
    312 
    313 
    314 //
    315 // Accessors::ScriptColumnOffset
    316 //
    317 
    318 
    319 MaybeObject* 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 
    327 const AccessorDescriptor Accessors::ScriptColumnOffset = {
    328   ScriptGetColumnOffset,
    329   IllegalSetter,
    330   0
    331 };
    332 
    333 
    334 //
    335 // Accessors::ScriptData
    336 //
    337 
    338 
    339 MaybeObject* 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 
    347 const AccessorDescriptor Accessors::ScriptData = {
    348   ScriptGetData,
    349   IllegalSetter,
    350   0
    351 };
    352 
    353 
    354 //
    355 // Accessors::ScriptType
    356 //
    357 
    358 
    359 MaybeObject* 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 
    367 const AccessorDescriptor Accessors::ScriptType = {
    368   ScriptGetType,
    369   IllegalSetter,
    370   0
    371 };
    372 
    373 
    374 //
    375 // Accessors::ScriptCompilationType
    376 //
    377 
    378 
    379 MaybeObject* 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 
    387 const AccessorDescriptor Accessors::ScriptCompilationType = {
    388   ScriptGetCompilationType,
    389   IllegalSetter,
    390   0
    391 };
    392 
    393 
    394 //
    395 // Accessors::ScriptGetLineEnds
    396 //
    397 
    398 
    399 MaybeObject* 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 
    417 const AccessorDescriptor Accessors::ScriptLineEnds = {
    418   ScriptGetLineEnds,
    419   IllegalSetter,
    420   0
    421 };
    422 
    423 
    424 //
    425 // Accessors::ScriptGetContextData
    426 //
    427 
    428 
    429 MaybeObject* 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 
    437 const AccessorDescriptor Accessors::ScriptContextData = {
    438   ScriptGetContextData,
    439   IllegalSetter,
    440   0
    441 };
    442 
    443 
    444 //
    445 // Accessors::ScriptGetEvalFromScript
    446 //
    447 
    448 
    449 MaybeObject* 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 
    466 const AccessorDescriptor Accessors::ScriptEvalFromScript = {
    467   ScriptGetEvalFromScript,
    468   IllegalSetter,
    469   0
    470 };
    471 
    472 
    473 //
    474 // Accessors::ScriptGetEvalFromScriptPosition
    475 //
    476 
    477 
    478 MaybeObject* 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 
    499 const AccessorDescriptor Accessors::ScriptEvalFromScriptPosition = {
    500   ScriptGetEvalFromScriptPosition,
    501   IllegalSetter,
    502   0
    503 };
    504 
    505 
    506 //
    507 // Accessors::ScriptGetEvalFromFunctionName
    508 //
    509 
    510 
    511 MaybeObject* 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 
    528 const AccessorDescriptor Accessors::ScriptEvalFromFunctionName = {
    529   ScriptGetEvalFromFunctionName,
    530   IllegalSetter,
    531   0
    532 };
    533 
    534 
    535 //
    536 // Accessors::FunctionPrototype
    537 //
    538 
    539 
    540 Handle<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 
    549 Handle<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 
    561 MaybeObject* 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 
    584 MaybeObject* 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 
    627 const AccessorDescriptor Accessors::FunctionPrototype = {
    628   FunctionGetPrototype,
    629   FunctionSetPrototype,
    630   0
    631 };
    632 
    633 
    634 //
    635 // Accessors::FunctionLength
    636 //
    637 
    638 
    639 MaybeObject* 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 
    659 const AccessorDescriptor Accessors::FunctionLength = {
    660   FunctionGetLength,
    661   ReadOnlySetAccessor,
    662   0
    663 };
    664 
    665 
    666 //
    667 // Accessors::FunctionName
    668 //
    669 
    670 
    671 MaybeObject* 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 
    681 const AccessorDescriptor Accessors::FunctionName = {
    682   FunctionGetName,
    683   ReadOnlySetAccessor,
    684   0
    685 };
    686 
    687 
    688 //
    689 // Accessors::FunctionArguments
    690 //
    691 
    692 
    693 Handle<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 
    702 static 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 
    729 MaybeObject* 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 
    795 const AccessorDescriptor Accessors::FunctionArguments = {
    796   FunctionGetArguments,
    797   ReadOnlySetAccessor,
    798   0
    799 };
    800 
    801 
    802 //
    803 // Accessors::FunctionCaller
    804 //
    805 
    806 
    807 class 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 
    853 MaybeObject* 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 
    905 const AccessorDescriptor Accessors::FunctionCaller = {
    906   FunctionGetCaller,
    907   ReadOnlySetAccessor,
    908   0
    909 };
    910 
    911 
    912 //
    913 // Accessors::MakeModuleExport
    914 //
    915 
    916 static 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 
    936 static 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 
    957 Handle<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