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 #ifndef V8_CONTEXTS_H_ 29 #define V8_CONTEXTS_H_ 30 31 namespace v8 { 32 namespace internal { 33 34 35 enum ContextLookupFlags { 36 FOLLOW_CONTEXT_CHAIN = 1, 37 FOLLOW_PROTOTYPE_CHAIN = 2, 38 39 DONT_FOLLOW_CHAINS = 0, 40 FOLLOW_CHAINS = FOLLOW_CONTEXT_CHAIN | FOLLOW_PROTOTYPE_CHAIN 41 }; 42 43 44 // Heap-allocated activation contexts. 45 // 46 // Contexts are implemented as FixedArray objects; the Context 47 // class is a convenience interface casted on a FixedArray object. 48 // 49 // Note: Context must have no virtual functions and Context objects 50 // must always be allocated via Heap::AllocateContext() or 51 // Factory::NewContext. 52 53 // Comment for special_function_table: 54 // Table for providing optimized/specialized functions. 55 // The array contains triplets [object, general_function, optimized_function]. 56 // Primarily added to support built-in optimized variants of 57 // Array.prototype.{push,pop}. 58 59 #define GLOBAL_CONTEXT_FIELDS(V) \ 60 V(GLOBAL_PROXY_INDEX, JSObject, global_proxy_object) \ 61 V(SECURITY_TOKEN_INDEX, Object, security_token) \ 62 V(BOOLEAN_FUNCTION_INDEX, JSFunction, boolean_function) \ 63 V(NUMBER_FUNCTION_INDEX, JSFunction, number_function) \ 64 V(STRING_FUNCTION_INDEX, JSFunction, string_function) \ 65 V(OBJECT_FUNCTION_INDEX, JSFunction, object_function) \ 66 V(ARRAY_FUNCTION_INDEX, JSFunction, array_function) \ 67 V(DATE_FUNCTION_INDEX, JSFunction, date_function) \ 68 V(JSON_OBJECT_INDEX, JSObject, json_object) \ 69 V(REGEXP_FUNCTION_INDEX, JSFunction, regexp_function) \ 70 V(INITIAL_OBJECT_PROTOTYPE_INDEX, JSObject, initial_object_prototype) \ 71 V(CREATE_DATE_FUN_INDEX, JSFunction, create_date_fun) \ 72 V(TO_NUMBER_FUN_INDEX, JSFunction, to_number_fun) \ 73 V(TO_STRING_FUN_INDEX, JSFunction, to_string_fun) \ 74 V(TO_DETAIL_STRING_FUN_INDEX, JSFunction, to_detail_string_fun) \ 75 V(TO_OBJECT_FUN_INDEX, JSFunction, to_object_fun) \ 76 V(TO_INTEGER_FUN_INDEX, JSFunction, to_integer_fun) \ 77 V(TO_UINT32_FUN_INDEX, JSFunction, to_uint32_fun) \ 78 V(TO_INT32_FUN_INDEX, JSFunction, to_int32_fun) \ 79 V(GLOBAL_EVAL_FUN_INDEX, JSFunction, global_eval_fun) \ 80 V(INSTANTIATE_FUN_INDEX, JSFunction, instantiate_fun) \ 81 V(CONFIGURE_INSTANCE_FUN_INDEX, JSFunction, configure_instance_fun) \ 82 V(FUNCTION_MAP_INDEX, Map, function_map) \ 83 V(FUNCTION_INSTANCE_MAP_INDEX, Map, function_instance_map) \ 84 V(JS_ARRAY_MAP_INDEX, Map, js_array_map)\ 85 V(SPECIAL_FUNCTION_TABLE_INDEX, FixedArray, special_function_table) \ 86 V(ARGUMENTS_BOILERPLATE_INDEX, JSObject, arguments_boilerplate) \ 87 V(MESSAGE_LISTENERS_INDEX, JSObject, message_listeners) \ 88 V(MAKE_MESSAGE_FUN_INDEX, JSFunction, make_message_fun) \ 89 V(GET_STACK_TRACE_LINE_INDEX, JSFunction, get_stack_trace_line_fun) \ 90 V(CONFIGURE_GLOBAL_INDEX, JSFunction, configure_global_fun) \ 91 V(FUNCTION_CACHE_INDEX, JSObject, function_cache) \ 92 V(RUNTIME_CONTEXT_INDEX, Context, runtime_context) \ 93 V(CALL_AS_FUNCTION_DELEGATE_INDEX, JSFunction, call_as_function_delegate) \ 94 V(CALL_AS_CONSTRUCTOR_DELEGATE_INDEX, JSFunction, \ 95 call_as_constructor_delegate) \ 96 V(SCRIPT_FUNCTION_INDEX, JSFunction, script_function) \ 97 V(CONTEXT_EXTENSION_FUNCTION_INDEX, JSFunction, context_extension_function) \ 98 V(OUT_OF_MEMORY_INDEX, Object, out_of_memory) \ 99 V(MAP_CACHE_INDEX, Object, map_cache) \ 100 V(CONTEXT_DATA_INDEX, Object, data) 101 102 // JSFunctions are pairs (context, function code), sometimes also called 103 // closures. A Context object is used to represent function contexts and 104 // dynamically pushed 'with' contexts (or 'scopes' in ECMA-262 speak). 105 // 106 // At runtime, the contexts build a stack in parallel to the execution 107 // stack, with the top-most context being the current context. All contexts 108 // have the following slots: 109 // 110 // [ closure ] This is the current function. It is the same for all 111 // contexts inside a function. It provides access to the 112 // incoming context (i.e., the outer context, which may 113 // or may not become the current function's context), and 114 // it provides access to the functions code and thus it's 115 // scope information, which in turn contains the names of 116 // statically allocated context slots. The names are needed 117 // for dynamic lookups in the presence of 'with' or 'eval'. 118 // 119 // [ fcontext ] A pointer to the innermost enclosing function context. 120 // It is the same for all contexts *allocated* inside a 121 // function, and the function context's fcontext points 122 // to itself. It is only needed for fast access of the 123 // function context (used for declarations, and static 124 // context slot access). 125 // 126 // [ previous ] A pointer to the previous context. It is NULL for 127 // function contexts, and non-NULL for 'with' contexts. 128 // Used to implement the 'with' statement. 129 // 130 // [ extension ] A pointer to an extension JSObject, or NULL. Used to 131 // implement 'with' statements and dynamic declarations 132 // (through 'eval'). The object in a 'with' statement is 133 // stored in the extension slot of a 'with' context. 134 // Dynamically declared variables/functions are also added 135 // to lazily allocated extension object. Context::Lookup 136 // searches the extension object for properties. 137 // 138 // [ global ] A pointer to the global object. Provided for quick 139 // access to the global object from inside the code (since 140 // we always have a context pointer). 141 // 142 // In addition, function contexts may have statically allocated context slots 143 // to store local variables/functions that are accessed from inner functions 144 // (via static context addresses) or through 'eval' (dynamic context lookups). 145 // Finally, the global context contains additional slots for fast access to 146 // global properties. 147 // 148 // We may be able to simplify the implementation: 149 // 150 // - We may be able to get rid of 'fcontext': We can always use the fact that 151 // previous == NULL for function contexts and so we can search for them. They 152 // are only needed when doing dynamic declarations, and the context chains 153 // tend to be very very short (depth of nesting of 'with' statements). At 154 // the moment we also use it in generated code for context slot accesses - 155 // and there we don't want a loop because of code bloat - but we may not 156 // need it there after all (see comment in codegen_*.cc). 157 // 158 // - If we cannot get rid of fcontext, consider making 'previous' never NULL 159 // except for the global context. This could simplify Context::Lookup. 160 161 class Context: public FixedArray { 162 public: 163 // Conversions. cast(Object * context)164 static Context* cast(Object* context) { 165 ASSERT(context->IsContext()); 166 return reinterpret_cast<Context*>(context); 167 } 168 169 // The default context slot layout; indices are FixedArray slot indices. 170 enum { 171 // These slots are in all contexts. 172 CLOSURE_INDEX, 173 FCONTEXT_INDEX, 174 PREVIOUS_INDEX, 175 EXTENSION_INDEX, 176 GLOBAL_INDEX, 177 MIN_CONTEXT_SLOTS, 178 179 // These slots are only in global contexts. 180 GLOBAL_PROXY_INDEX = MIN_CONTEXT_SLOTS, 181 SECURITY_TOKEN_INDEX, 182 ARGUMENTS_BOILERPLATE_INDEX, 183 JS_ARRAY_MAP_INDEX, 184 FUNCTION_MAP_INDEX, 185 FUNCTION_INSTANCE_MAP_INDEX, 186 INITIAL_OBJECT_PROTOTYPE_INDEX, 187 BOOLEAN_FUNCTION_INDEX, 188 NUMBER_FUNCTION_INDEX, 189 STRING_FUNCTION_INDEX, 190 OBJECT_FUNCTION_INDEX, 191 ARRAY_FUNCTION_INDEX, 192 DATE_FUNCTION_INDEX, 193 JSON_OBJECT_INDEX, 194 REGEXP_FUNCTION_INDEX, 195 CREATE_DATE_FUN_INDEX, 196 TO_NUMBER_FUN_INDEX, 197 TO_STRING_FUN_INDEX, 198 TO_DETAIL_STRING_FUN_INDEX, 199 TO_OBJECT_FUN_INDEX, 200 TO_INTEGER_FUN_INDEX, 201 TO_UINT32_FUN_INDEX, 202 TO_INT32_FUN_INDEX, 203 TO_BOOLEAN_FUN_INDEX, 204 GLOBAL_EVAL_FUN_INDEX, 205 INSTANTIATE_FUN_INDEX, 206 CONFIGURE_INSTANCE_FUN_INDEX, 207 SPECIAL_FUNCTION_TABLE_INDEX, 208 MESSAGE_LISTENERS_INDEX, 209 MAKE_MESSAGE_FUN_INDEX, 210 GET_STACK_TRACE_LINE_INDEX, 211 CONFIGURE_GLOBAL_INDEX, 212 FUNCTION_CACHE_INDEX, 213 RUNTIME_CONTEXT_INDEX, 214 CALL_AS_FUNCTION_DELEGATE_INDEX, 215 CALL_AS_CONSTRUCTOR_DELEGATE_INDEX, 216 SCRIPT_FUNCTION_INDEX, 217 CONTEXT_EXTENSION_FUNCTION_INDEX, 218 OUT_OF_MEMORY_INDEX, 219 MAP_CACHE_INDEX, 220 CONTEXT_DATA_INDEX, 221 GLOBAL_CONTEXT_SLOTS 222 }; 223 224 // Direct slot access. closure()225 JSFunction* closure() { return JSFunction::cast(get(CLOSURE_INDEX)); } set_closure(JSFunction * closure)226 void set_closure(JSFunction* closure) { set(CLOSURE_INDEX, closure); } 227 fcontext()228 Context* fcontext() { return Context::cast(get(FCONTEXT_INDEX)); } set_fcontext(Context * context)229 void set_fcontext(Context* context) { set(FCONTEXT_INDEX, context); } 230 previous()231 Context* previous() { 232 Object* result = unchecked_previous(); 233 ASSERT(IsBootstrappingOrContext(result)); 234 return reinterpret_cast<Context*>(result); 235 } set_previous(Context * context)236 void set_previous(Context* context) { set(PREVIOUS_INDEX, context); } 237 has_extension()238 bool has_extension() { return unchecked_extension() != NULL; } extension()239 JSObject* extension() { return JSObject::cast(unchecked_extension()); } set_extension(JSObject * object)240 void set_extension(JSObject* object) { set(EXTENSION_INDEX, object); } 241 global()242 GlobalObject* global() { 243 Object* result = get(GLOBAL_INDEX); 244 ASSERT(IsBootstrappingOrGlobalObject(result)); 245 return reinterpret_cast<GlobalObject*>(result); 246 } set_global(GlobalObject * global)247 void set_global(GlobalObject* global) { set(GLOBAL_INDEX, global); } 248 249 // Returns a JSGlobalProxy object or null. 250 JSObject* global_proxy(); 251 void set_global_proxy(JSObject* global); 252 253 // The builtins object. 254 JSBuiltinsObject* builtins(); 255 256 // Compute the global context by traversing the context chain. 257 Context* global_context(); 258 259 // Tells if this is a function context (as opposed to a 'with' context). is_function_context()260 bool is_function_context() { return unchecked_previous() == NULL; } 261 262 // Tells whether the global context is marked with out of memory. has_out_of_memory()263 bool has_out_of_memory() { 264 return global_context()->out_of_memory() == Heap::true_value(); 265 } 266 267 // Mark the global context with out of memory. mark_out_of_memory()268 void mark_out_of_memory() { 269 global_context()->set_out_of_memory(Heap::true_value()); 270 } 271 272 // The exception holder is the object used as a with object in 273 // the implementation of a catch block. is_exception_holder(Object * object)274 bool is_exception_holder(Object* object) { 275 return IsCatchContext() && extension() == object; 276 } 277 278 #define GLOBAL_CONTEXT_FIELD_ACCESSORS(index, type, name) \ 279 void set_##name(type* value) { \ 280 ASSERT(IsGlobalContext()); \ 281 set(index, value); \ 282 } \ 283 type* name() { \ 284 ASSERT(IsGlobalContext()); \ 285 return type::cast(get(index)); \ 286 } 287 GLOBAL_CONTEXT_FIELDS(GLOBAL_CONTEXT_FIELD_ACCESSORS) 288 #undef GLOBAL_CONTEXT_FIELD_ACCESSORS 289 290 // Lookup the the slot called name, starting with the current context. 291 // There are 4 possible outcomes: 292 // 293 // 1) index_ >= 0 && result->IsContext(): 294 // most common case, the result is a Context, and index is the 295 // context slot index, and the slot exists. 296 // attributes == READ_ONLY for the function name variable, NONE otherwise. 297 // 298 // 2) index_ >= 0 && result->IsJSObject(): 299 // the result is the JSObject arguments object, the index is the parameter 300 // index, i.e., key into the arguments object, and the property exists. 301 // attributes != ABSENT. 302 // 303 // 3) index_ < 0 && result->IsJSObject(): 304 // the result is the JSObject extension context or the global object, 305 // and the name is the property name, and the property exists. 306 // attributes != ABSENT. 307 // 308 // 4) index_ < 0 && result.is_null(): 309 // there was no context found with the corresponding property. 310 // attributes == ABSENT. 311 Handle<Object> Lookup(Handle<String> name, ContextLookupFlags flags, 312 int* index_, PropertyAttributes* attributes); 313 314 // Determine if a local variable with the given name exists in a 315 // context. Do not consider context extension objects. This is 316 // used for compiling code using eval. If the context surrounding 317 // the eval call does not have a local variable with this name and 318 // does not contain a with statement the property is global unless 319 // it is shadowed by a property in an extension object introduced by 320 // eval. 321 bool GlobalIfNotShadowedByEval(Handle<String> name); 322 323 // Code generation support. SlotOffset(int index)324 static int SlotOffset(int index) { 325 return kHeaderSize + index * kPointerSize - kHeapObjectTag; 326 } 327 328 private: 329 // Unchecked access to the slots. unchecked_previous()330 Object* unchecked_previous() { return get(PREVIOUS_INDEX); } unchecked_extension()331 Object* unchecked_extension() { return get(EXTENSION_INDEX); } 332 333 #ifdef DEBUG 334 // Bootstrapping-aware type checks. 335 static bool IsBootstrappingOrContext(Object* object); 336 static bool IsBootstrappingOrGlobalObject(Object* object); 337 #endif 338 }; 339 340 } } // namespace v8::internal 341 342 #endif // V8_CONTEXTS_H_ 343