The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.

Please select the desired protocol below to get the URL.

This URL has Read-Only access.

Statistics
| Branch: | Revision:

main_repo / deps / v8 / src / contexts.cc @ f230a1cf

History | View | Annotate | Download (13.3 KB)

1
// Copyright 2011 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
Context* Context::declaration_context() {
38
  Context* current = this;
39
  while (!current->IsFunctionContext() && !current->IsNativeContext()) {
40
    current = current->previous();
41
    ASSERT(current->closure() == closure());
42
  }
43
  return current;
44
}
45

    
46

    
47
JSBuiltinsObject* Context::builtins() {
48
  GlobalObject* object = global_object();
49
  if (object->IsJSGlobalObject()) {
50
    return JSGlobalObject::cast(object)->builtins();
51
  } else {
52
    ASSERT(object->IsJSBuiltinsObject());
53
    return JSBuiltinsObject::cast(object);
54
  }
55
}
56

    
57

    
58
Context* Context::global_context() {
59
  Context* current = this;
60
  while (!current->IsGlobalContext()) {
61
    current = current->previous();
62
  }
63
  return current;
64
}
65

    
66

    
67
Context* Context::native_context() {
68
  // Fast case: the global object for this context has been set.  In
69
  // that case, the global object has a direct pointer to the global
70
  // context.
71
  if (global_object()->IsGlobalObject()) {
72
    return global_object()->native_context();
73
  }
74

    
75
  // During bootstrapping, the global object might not be set and we
76
  // have to search the context chain to find the native context.
77
  ASSERT(this->GetIsolate()->bootstrapper()->IsActive());
78
  Context* current = this;
79
  while (!current->IsNativeContext()) {
80
    JSFunction* closure = JSFunction::cast(current->closure());
81
    current = Context::cast(closure->context());
82
  }
83
  return current;
84
}
85

    
86

    
87
JSObject* Context::global_proxy() {
88
  return native_context()->global_proxy_object();
89
}
90

    
91

    
92
void Context::set_global_proxy(JSObject* object) {
93
  native_context()->set_global_proxy_object(object);
94
}
95

    
96

    
97
Handle<Object> Context::Lookup(Handle<String> name,
98
                               ContextLookupFlags flags,
99
                               int* index,
100
                               PropertyAttributes* attributes,
101
                               BindingFlags* binding_flags) {
102
  Isolate* isolate = GetIsolate();
103
  Handle<Context> context(this, isolate);
104

    
105
  bool follow_context_chain = (flags & FOLLOW_CONTEXT_CHAIN) != 0;
106
  *index = -1;
107
  *attributes = ABSENT;
108
  *binding_flags = MISSING_BINDING;
109

    
110
  if (FLAG_trace_contexts) {
111
    PrintF("Context::Lookup(");
112
    name->ShortPrint();
113
    PrintF(")\n");
114
  }
115

    
116
  do {
117
    if (FLAG_trace_contexts) {
118
      PrintF(" - looking in context %p", reinterpret_cast<void*>(*context));
119
      if (context->IsNativeContext()) PrintF(" (native context)");
120
      PrintF("\n");
121
    }
122

    
123
    // 1. Check global objects, subjects of with, and extension objects.
124
    if (context->IsNativeContext() ||
125
        context->IsWithContext() ||
126
        (context->IsFunctionContext() && context->has_extension())) {
127
      Handle<JSReceiver> object(
128
          JSReceiver::cast(context->extension()), isolate);
129
      // Context extension objects needs to behave as if they have no
130
      // prototype.  So even if we want to follow prototype chains, we need
131
      // to only do a local lookup for context extension objects.
132
      if ((flags & FOLLOW_PROTOTYPE_CHAIN) == 0 ||
133
          object->IsJSContextExtensionObject()) {
134
        *attributes = object->GetLocalPropertyAttribute(*name);
135
      } else {
136
        *attributes = object->GetPropertyAttribute(*name);
137
      }
138
      if (isolate->has_pending_exception()) return Handle<Object>();
139

    
140
      if (*attributes != ABSENT) {
141
        if (FLAG_trace_contexts) {
142
          PrintF("=> found property in context object %p\n",
143
                 reinterpret_cast<void*>(*object));
144
        }
145
        return object;
146
      }
147
    }
148

    
149
    // 2. Check the context proper if it has slots.
150
    if (context->IsFunctionContext() || context->IsBlockContext()) {
151
      // Use serialized scope information of functions and blocks to search
152
      // for the context index.
153
      Handle<ScopeInfo> scope_info;
154
      if (context->IsFunctionContext()) {
155
        scope_info = Handle<ScopeInfo>(
156
            context->closure()->shared()->scope_info(), isolate);
157
      } else {
158
        scope_info = Handle<ScopeInfo>(
159
            ScopeInfo::cast(context->extension()), isolate);
160
      }
161
      VariableMode mode;
162
      InitializationFlag init_flag;
163
      int slot_index = scope_info->ContextSlotIndex(*name, &mode, &init_flag);
164
      ASSERT(slot_index < 0 || slot_index >= MIN_CONTEXT_SLOTS);
165
      if (slot_index >= 0) {
166
        if (FLAG_trace_contexts) {
167
          PrintF("=> found local in context slot %d (mode = %d)\n",
168
                 slot_index, mode);
169
        }
170
        *index = slot_index;
171
        // Note: Fixed context slots are statically allocated by the compiler.
172
        // Statically allocated variables always have a statically known mode,
173
        // which is the mode with which they were declared when added to the
174
        // scope. Thus, the DYNAMIC mode (which corresponds to dynamically
175
        // declared variables that were introduced through declaration nodes)
176
        // must not appear here.
177
        switch (mode) {
178
          case INTERNAL:  // Fall through.
179
          case VAR:
180
            *attributes = NONE;
181
            *binding_flags = MUTABLE_IS_INITIALIZED;
182
            break;
183
          case LET:
184
            *attributes = NONE;
185
            *binding_flags = (init_flag == kNeedsInitialization)
186
                ? MUTABLE_CHECK_INITIALIZED : MUTABLE_IS_INITIALIZED;
187
            break;
188
          case CONST:
189
            *attributes = READ_ONLY;
190
            *binding_flags = (init_flag == kNeedsInitialization)
191
                ? IMMUTABLE_CHECK_INITIALIZED : IMMUTABLE_IS_INITIALIZED;
192
            break;
193
          case CONST_HARMONY:
194
            *attributes = READ_ONLY;
195
            *binding_flags = (init_flag == kNeedsInitialization)
196
                ? IMMUTABLE_CHECK_INITIALIZED_HARMONY :
197
                IMMUTABLE_IS_INITIALIZED_HARMONY;
198
            break;
199
          case MODULE:
200
            *attributes = READ_ONLY;
201
            *binding_flags = IMMUTABLE_IS_INITIALIZED_HARMONY;
202
            break;
203
          case DYNAMIC:
204
          case DYNAMIC_GLOBAL:
205
          case DYNAMIC_LOCAL:
206
          case TEMPORARY:
207
            UNREACHABLE();
208
            break;
209
        }
210
        return context;
211
      }
212

    
213
      // Check the slot corresponding to the intermediate context holding
214
      // only the function name variable.
215
      if (follow_context_chain && context->IsFunctionContext()) {
216
        VariableMode mode;
217
        int function_index = scope_info->FunctionContextSlotIndex(*name, &mode);
218
        if (function_index >= 0) {
219
          if (FLAG_trace_contexts) {
220
            PrintF("=> found intermediate function in context slot %d\n",
221
                   function_index);
222
          }
223
          *index = function_index;
224
          *attributes = READ_ONLY;
225
          ASSERT(mode == CONST || mode == CONST_HARMONY);
226
          *binding_flags = (mode == CONST)
227
              ? IMMUTABLE_IS_INITIALIZED : IMMUTABLE_IS_INITIALIZED_HARMONY;
228
          return context;
229
        }
230
      }
231

    
232
    } else if (context->IsCatchContext()) {
233
      // Catch contexts have the variable name in the extension slot.
234
      if (name->Equals(String::cast(context->extension()))) {
235
        if (FLAG_trace_contexts) {
236
          PrintF("=> found in catch context\n");
237
        }
238
        *index = Context::THROWN_OBJECT_INDEX;
239
        *attributes = NONE;
240
        *binding_flags = MUTABLE_IS_INITIALIZED;
241
        return context;
242
      }
243
    }
244

    
245
    // 3. Prepare to continue with the previous (next outermost) context.
246
    if (context->IsNativeContext()) {
247
      follow_context_chain = false;
248
    } else {
249
      context = Handle<Context>(context->previous(), isolate);
250
    }
251
  } while (follow_context_chain);
252

    
253
  if (FLAG_trace_contexts) {
254
    PrintF("=> no property/slot found\n");
255
  }
256
  return Handle<Object>::null();
257
}
258

    
259

    
260
void Context::AddOptimizedFunction(JSFunction* function) {
261
  ASSERT(IsNativeContext());
262
#ifdef ENABLE_SLOW_ASSERTS
263
  if (FLAG_enable_slow_asserts) {
264
    Object* element = get(OPTIMIZED_FUNCTIONS_LIST);
265
    while (!element->IsUndefined()) {
266
      CHECK(element != function);
267
      element = JSFunction::cast(element)->next_function_link();
268
    }
269
  }
270

    
271
  // Check that the context belongs to the weak native contexts list.
272
  bool found = false;
273
  Object* context = GetHeap()->native_contexts_list();
274
  while (!context->IsUndefined()) {
275
    if (context == this) {
276
      found = true;
277
      break;
278
    }
279
    context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK);
280
  }
281
  CHECK(found);
282
#endif
283

    
284
  // If the function link field is already used then the function was
285
  // enqueued as a code flushing candidate and we remove it now.
286
  if (!function->next_function_link()->IsUndefined()) {
287
    CodeFlusher* flusher = GetHeap()->mark_compact_collector()->code_flusher();
288
    flusher->EvictCandidate(function);
289
  }
290

    
291
  ASSERT(function->next_function_link()->IsUndefined());
292

    
293
  function->set_next_function_link(get(OPTIMIZED_FUNCTIONS_LIST));
294
  set(OPTIMIZED_FUNCTIONS_LIST, function);
295
}
296

    
297

    
298
void Context::RemoveOptimizedFunction(JSFunction* function) {
299
  ASSERT(IsNativeContext());
300
  Object* element = get(OPTIMIZED_FUNCTIONS_LIST);
301
  JSFunction* prev = NULL;
302
  while (!element->IsUndefined()) {
303
    JSFunction* element_function = JSFunction::cast(element);
304
    ASSERT(element_function->next_function_link()->IsUndefined() ||
305
           element_function->next_function_link()->IsJSFunction());
306
    if (element_function == function) {
307
      if (prev == NULL) {
308
        set(OPTIMIZED_FUNCTIONS_LIST, element_function->next_function_link());
309
      } else {
310
        prev->set_next_function_link(element_function->next_function_link());
311
      }
312
      element_function->set_next_function_link(GetHeap()->undefined_value());
313
      return;
314
    }
315
    prev = element_function;
316
    element = element_function->next_function_link();
317
  }
318
  UNREACHABLE();
319
}
320

    
321

    
322
void Context::SetOptimizedFunctionsListHead(Object* head) {
323
  ASSERT(IsNativeContext());
324
  set(OPTIMIZED_FUNCTIONS_LIST, head);
325
}
326

    
327

    
328
Object* Context::OptimizedFunctionsListHead() {
329
  ASSERT(IsNativeContext());
330
  return get(OPTIMIZED_FUNCTIONS_LIST);
331
}
332

    
333

    
334
void Context::AddOptimizedCode(Code* code) {
335
  ASSERT(IsNativeContext());
336
  ASSERT(code->kind() == Code::OPTIMIZED_FUNCTION);
337
  ASSERT(code->next_code_link()->IsUndefined());
338
  code->set_next_code_link(get(OPTIMIZED_CODE_LIST));
339
  set(OPTIMIZED_CODE_LIST, code);
340
}
341

    
342

    
343
void Context::SetOptimizedCodeListHead(Object* head) {
344
  ASSERT(IsNativeContext());
345
  set(OPTIMIZED_CODE_LIST, head);
346
}
347

    
348

    
349
Object* Context::OptimizedCodeListHead() {
350
  ASSERT(IsNativeContext());
351
  return get(OPTIMIZED_CODE_LIST);
352
}
353

    
354

    
355
void Context::SetDeoptimizedCodeListHead(Object* head) {
356
  ASSERT(IsNativeContext());
357
  set(DEOPTIMIZED_CODE_LIST, head);
358
}
359

    
360

    
361
Object* Context::DeoptimizedCodeListHead() {
362
  ASSERT(IsNativeContext());
363
  return get(DEOPTIMIZED_CODE_LIST);
364
}
365

    
366

    
367
Handle<Object> Context::ErrorMessageForCodeGenerationFromStrings() {
368
  Handle<Object> result(error_message_for_code_gen_from_strings(),
369
                        GetIsolate());
370
  if (!result->IsUndefined()) return result;
371
  return GetIsolate()->factory()->NewStringFromAscii(i::CStrVector(
372
      "Code generation from strings disallowed for this context"));
373
}
374

    
375

    
376
#ifdef DEBUG
377
bool Context::IsBootstrappingOrValidParentContext(
378
    Object* object, Context* child) {
379
  // During bootstrapping we allow all objects to pass as
380
  // contexts. This is necessary to fix circular dependencies.
381
  if (child->GetIsolate()->bootstrapper()->IsActive()) return true;
382
  if (!object->IsContext()) return false;
383
  Context* context = Context::cast(object);
384
  return context->IsNativeContext() || context->IsGlobalContext() ||
385
         context->IsModuleContext() || !child->IsModuleContext();
386
}
387

    
388

    
389
bool Context::IsBootstrappingOrGlobalObject(Isolate* isolate, Object* object) {
390
  // During bootstrapping we allow all objects to pass as global
391
  // objects. This is necessary to fix circular dependencies.
392
  return isolate->heap()->gc_state() != Heap::NOT_IN_GC ||
393
      isolate->bootstrapper()->IsActive() ||
394
      object->IsGlobalObject();
395
}
396
#endif
397

    
398
} }  // namespace v8::internal