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 "bootstrapper.h"
     31 #include "debug.h"
     32 #include "scopeinfo.h"
     33 
     34 namespace v8 {
     35 namespace internal {
     36 
     37 JSBuiltinsObject* Context::builtins() {
     38   GlobalObject* object = global();
     39   if (object->IsJSGlobalObject()) {
     40     return JSGlobalObject::cast(object)->builtins();
     41   } else {
     42     ASSERT(object->IsJSBuiltinsObject());
     43     return JSBuiltinsObject::cast(object);
     44   }
     45 }
     46 
     47 
     48 Context* Context::global_context() {
     49   // Fast case: the global object for this context has been set.  In
     50   // that case, the global object has a direct pointer to the global
     51   // context.
     52   if (global()->IsGlobalObject()) {
     53     return global()->global_context();
     54   }
     55 
     56   // During bootstrapping, the global object might not be set and we
     57   // have to search the context chain to find the global context.
     58   ASSERT(Bootstrapper::IsActive());
     59   Context* current = this;
     60   while (!current->IsGlobalContext()) {
     61     JSFunction* closure = JSFunction::cast(current->closure());
     62     current = Context::cast(closure->context());
     63   }
     64   return current;
     65 }
     66 
     67 
     68 JSObject* Context::global_proxy() {
     69   return global_context()->global_proxy_object();
     70 }
     71 
     72 void Context::set_global_proxy(JSObject* object) {
     73   global_context()->set_global_proxy_object(object);
     74 }
     75 
     76 
     77 Handle<Object> Context::Lookup(Handle<String> name, ContextLookupFlags flags,
     78                                int* index_, PropertyAttributes* attributes) {
     79   Handle<Context> context(this);
     80 
     81   bool follow_context_chain = (flags & FOLLOW_CONTEXT_CHAIN) != 0;
     82   *index_ = -1;
     83   *attributes = ABSENT;
     84 
     85   if (FLAG_trace_contexts) {
     86     PrintF("Context::Lookup(");
     87     name->ShortPrint();
     88     PrintF(")\n");
     89   }
     90 
     91   do {
     92     if (FLAG_trace_contexts) {
     93       PrintF(" - looking in context %p", *context);
     94       if (context->IsGlobalContext()) PrintF(" (global context)");
     95       PrintF("\n");
     96     }
     97 
     98     // check extension/with object
     99     if (context->has_extension()) {
    100       Handle<JSObject> extension = Handle<JSObject>(context->extension());
    101       // Context extension objects needs to behave as if they have no
    102       // prototype.  So even if we want to follow prototype chains, we
    103       // need to only do a local lookup for context extension objects.
    104       if ((flags & FOLLOW_PROTOTYPE_CHAIN) == 0 ||
    105           extension->IsJSContextExtensionObject()) {
    106         *attributes = extension->GetLocalPropertyAttribute(*name);
    107       } else {
    108         *attributes = extension->GetPropertyAttribute(*name);
    109       }
    110       if (*attributes != ABSENT) {
    111         // property found
    112         if (FLAG_trace_contexts) {
    113           PrintF("=> found property in context object %p\n", *extension);
    114         }
    115         return extension;
    116       }
    117     }
    118 
    119     if (context->is_function_context()) {
    120       // we have context-local slots
    121 
    122       // check non-parameter locals in context
    123       Handle<Code> code(context->closure()->code());
    124       Variable::Mode mode;
    125       int index = ScopeInfo<>::ContextSlotIndex(*code, *name, &mode);
    126       ASSERT(index < 0 || index >= MIN_CONTEXT_SLOTS);
    127       if (index >= 0) {
    128         // slot found
    129         if (FLAG_trace_contexts) {
    130           PrintF("=> found local in context slot %d (mode = %d)\n",
    131                  index, mode);
    132         }
    133         *index_ = index;
    134         // Note: Fixed context slots are statically allocated by the compiler.
    135         // Statically allocated variables always have a statically known mode,
    136         // which is the mode with which they were declared when added to the
    137         // scope. Thus, the DYNAMIC mode (which corresponds to dynamically
    138         // declared variables that were introduced through declaration nodes)
    139         // must not appear here.
    140         switch (mode) {
    141           case Variable::INTERNAL:  // fall through
    142           case Variable::VAR: *attributes = NONE; break;
    143           case Variable::CONST: *attributes = READ_ONLY; break;
    144           case Variable::DYNAMIC: UNREACHABLE(); break;
    145           case Variable::DYNAMIC_GLOBAL: UNREACHABLE(); break;
    146           case Variable::DYNAMIC_LOCAL: UNREACHABLE(); break;
    147           case Variable::TEMPORARY: UNREACHABLE(); break;
    148         }
    149         return context;
    150       }
    151 
    152       // check parameter locals in context
    153       int param_index = ScopeInfo<>::ParameterIndex(*code, *name);
    154       if (param_index >= 0) {
    155         // slot found.
    156         int index =
    157             ScopeInfo<>::ContextSlotIndex(*code,
    158                                           Heap::arguments_shadow_symbol(),
    159                                           NULL);
    160         ASSERT(index >= 0);  // arguments must exist and be in the heap context
    161         Handle<JSObject> arguments(JSObject::cast(context->get(index)));
    162         ASSERT(arguments->HasLocalProperty(Heap::length_symbol()));
    163         if (FLAG_trace_contexts) {
    164           PrintF("=> found parameter %d in arguments object\n", param_index);
    165         }
    166         *index_ = param_index;
    167         *attributes = NONE;
    168         return arguments;
    169       }
    170 
    171       // check intermediate context (holding only the function name variable)
    172       if (follow_context_chain) {
    173         int index = ScopeInfo<>::FunctionContextSlotIndex(*code, *name);
    174         if (index >= 0) {
    175           // slot found
    176           if (FLAG_trace_contexts) {
    177             PrintF("=> found intermediate function in context slot %d\n",
    178                    index);
    179           }
    180           *index_ = index;
    181           *attributes = READ_ONLY;
    182           return context;
    183         }
    184       }
    185     }
    186 
    187     // proceed with enclosing context
    188     if (context->IsGlobalContext()) {
    189       follow_context_chain = false;
    190     } else if (context->is_function_context()) {
    191       context = Handle<Context>(Context::cast(context->closure()->context()));
    192     } else {
    193       context = Handle<Context>(context->previous());
    194     }
    195   } while (follow_context_chain);
    196 
    197   // slot not found
    198   if (FLAG_trace_contexts) {
    199     PrintF("=> no property/slot found\n");
    200   }
    201   return Handle<Object>::null();
    202 }
    203 
    204 
    205 bool Context::GlobalIfNotShadowedByEval(Handle<String> name) {
    206   Context* context = this;
    207 
    208   // Check that there is no local with the given name in contexts
    209   // before the global context and check that there are no context
    210   // extension objects (conservative check for with statements).
    211   while (!context->IsGlobalContext()) {
    212     // Check if the context is a potentially a with context.
    213     if (context->has_extension()) return false;
    214 
    215     // Not a with context so it must be a function context.
    216     ASSERT(context->is_function_context());
    217 
    218     // Check non-parameter locals.
    219     Handle<Code> code(context->closure()->code());
    220     Variable::Mode mode;
    221     int index = ScopeInfo<>::ContextSlotIndex(*code, *name, &mode);
    222     ASSERT(index < 0 || index >= MIN_CONTEXT_SLOTS);
    223     if (index >= 0) return false;
    224 
    225     // Check parameter locals.
    226     int param_index = ScopeInfo<>::ParameterIndex(*code, *name);
    227     if (param_index >= 0) return false;
    228 
    229     // Check context only holding the function name variable.
    230     index = ScopeInfo<>::FunctionContextSlotIndex(*code, *name);
    231     if (index >= 0) return false;
    232     context = Context::cast(context->closure()->context());
    233   }
    234 
    235   // No local or potential with statement found so the variable is
    236   // global unless it is shadowed by an eval-introduced variable.
    237   return true;
    238 }
    239 
    240 
    241 #ifdef DEBUG
    242 bool Context::IsBootstrappingOrContext(Object* object) {
    243   // During bootstrapping we allow all objects to pass as
    244   // contexts. This is necessary to fix circular dependencies.
    245   return Bootstrapper::IsActive() || object->IsContext();
    246 }
    247 
    248 
    249 bool Context::IsBootstrappingOrGlobalObject(Object* object) {
    250   // During bootstrapping we allow all objects to pass as global
    251   // objects. This is necessary to fix circular dependencies.
    252   return Bootstrapper::IsActive() || object->IsGlobalObject();
    253 }
    254 #endif
    255 
    256 } }  // namespace v8::internal
    257