blob: 1ce5007d88f018a9e19d9975820e45176524fb97 [file] [log] [blame]
Steve Blocka7e24c12009-10-30 11:49:00 +00001// 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
34namespace v8 {
35namespace internal {
36
37JSBuiltinsObject* 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
48Context* 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 }
Leon Clarkee46be812010-01-19 14:06:41 +000055
Steve Blocka7e24c12009-10-30 11:49:00 +000056 // During bootstrapping, the global object might not be set and we
57 // have to search the context chain to find the global context.
Leon Clarkee46be812010-01-19 14:06:41 +000058 ASSERT(Bootstrapper::IsActive());
Steve Blocka7e24c12009-10-30 11:49:00 +000059 Context* current = this;
60 while (!current->IsGlobalContext()) {
Leon Clarkee46be812010-01-19 14:06:41 +000061 JSFunction* closure = JSFunction::cast(current->closure());
62 current = Context::cast(closure->context());
Steve Blocka7e24c12009-10-30 11:49:00 +000063 }
64 return current;
65}
66
67
68JSObject* Context::global_proxy() {
69 return global_context()->global_proxy_object();
70}
71
72void Context::set_global_proxy(JSObject* object) {
73 global_context()->set_global_proxy_object(object);
74}
75
76
77Handle<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) {
Ben Murdochf87a2032010-10-22 12:50:53 +010093 PrintF(" - looking in context %p", reinterpret_cast<void*>(*context));
Steve Blocka7e24c12009-10-30 11:49:00 +000094 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) {
Ben Murdochf87a2032010-10-22 12:50:53 +0100113 PrintF("=> found property in context object %p\n",
114 reinterpret_cast<void*>(*extension));
Steve Blocka7e24c12009-10-30 11:49:00 +0000115 }
116 return extension;
117 }
118 }
119
120 if (context->is_function_context()) {
121 // we have context-local slots
122
123 // check non-parameter locals in context
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100124 Handle<SerializedScopeInfo> scope_info(
125 context->closure()->shared()->scope_info());
Steve Blocka7e24c12009-10-30 11:49:00 +0000126 Variable::Mode mode;
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100127 int index = scope_info->ContextSlotIndex(*name, &mode);
Steve Blocka7e24c12009-10-30 11:49:00 +0000128 ASSERT(index < 0 || index >= MIN_CONTEXT_SLOTS);
129 if (index >= 0) {
130 // slot found
131 if (FLAG_trace_contexts) {
132 PrintF("=> found local in context slot %d (mode = %d)\n",
133 index, mode);
134 }
135 *index_ = index;
136 // Note: Fixed context slots are statically allocated by the compiler.
137 // Statically allocated variables always have a statically known mode,
138 // which is the mode with which they were declared when added to the
139 // scope. Thus, the DYNAMIC mode (which corresponds to dynamically
140 // declared variables that were introduced through declaration nodes)
141 // must not appear here.
142 switch (mode) {
143 case Variable::INTERNAL: // fall through
144 case Variable::VAR: *attributes = NONE; break;
145 case Variable::CONST: *attributes = READ_ONLY; break;
146 case Variable::DYNAMIC: UNREACHABLE(); break;
147 case Variable::DYNAMIC_GLOBAL: UNREACHABLE(); break;
148 case Variable::DYNAMIC_LOCAL: UNREACHABLE(); break;
149 case Variable::TEMPORARY: UNREACHABLE(); break;
150 }
151 return context;
152 }
153
154 // check parameter locals in context
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100155 int param_index = scope_info->ParameterIndex(*name);
Steve Blocka7e24c12009-10-30 11:49:00 +0000156 if (param_index >= 0) {
157 // slot found.
158 int index =
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100159 scope_info->ContextSlotIndex(Heap::arguments_shadow_symbol(), NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +0000160 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) {
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100173 int index = scope_info->FunctionContextSlotIndex(*name);
Steve Blocka7e24c12009-10-30 11:49:00 +0000174 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
205bool 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.
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100219 Handle<SerializedScopeInfo> scope_info(
220 context->closure()->shared()->scope_info());
Steve Blocka7e24c12009-10-30 11:49:00 +0000221 Variable::Mode mode;
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100222 int index = scope_info->ContextSlotIndex(*name, &mode);
Steve Blocka7e24c12009-10-30 11:49:00 +0000223 ASSERT(index < 0 || index >= MIN_CONTEXT_SLOTS);
224 if (index >= 0) return false;
225
226 // Check parameter locals.
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100227 int param_index = scope_info->ParameterIndex(*name);
Steve Blocka7e24c12009-10-30 11:49:00 +0000228 if (param_index >= 0) return false;
229
230 // Check context only holding the function name variable.
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100231 index = scope_info->FunctionContextSlotIndex(*name);
Steve Blocka7e24c12009-10-30 11:49:00 +0000232 if (index >= 0) return false;
233 context = Context::cast(context->closure()->context());
234 }
235
236 // No local or potential with statement found so the variable is
237 // global unless it is shadowed by an eval-introduced variable.
238 return true;
239}
240
241
242#ifdef DEBUG
243bool Context::IsBootstrappingOrContext(Object* object) {
244 // During bootstrapping we allow all objects to pass as
245 // contexts. This is necessary to fix circular dependencies.
246 return Bootstrapper::IsActive() || object->IsContext();
247}
248
249
250bool Context::IsBootstrappingOrGlobalObject(Object* object) {
251 // During bootstrapping we allow all objects to pass as global
252 // objects. This is necessary to fix circular dependencies.
253 return Bootstrapper::IsActive() || object->IsGlobalObject();
254}
255#endif
256
257} } // namespace v8::internal