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