js/src/frontend/SharedContext.h

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
michael@0 2 * vim: set ts=8 sts=4 et sw=4 tw=99:
michael@0 3 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #ifndef frontend_SharedContext_h
michael@0 8 #define frontend_SharedContext_h
michael@0 9
michael@0 10 #include "jsatom.h"
michael@0 11 #include "jsopcode.h"
michael@0 12 #include "jspubtd.h"
michael@0 13 #include "jsscript.h"
michael@0 14 #include "jstypes.h"
michael@0 15
michael@0 16 #include "frontend/ParseMaps.h"
michael@0 17 #include "frontend/ParseNode.h"
michael@0 18 #include "frontend/TokenStream.h"
michael@0 19 #include "vm/ScopeObject.h"
michael@0 20
michael@0 21 namespace js {
michael@0 22 namespace frontend {
michael@0 23
michael@0 24 // These flags apply to both global and function contexts.
michael@0 25 class AnyContextFlags
michael@0 26 {
michael@0 27 // This class's data is all private and so only visible to these friends.
michael@0 28 friend class SharedContext;
michael@0 29
michael@0 30 // True if "use strict"; appears in the body instead of being inherited.
michael@0 31 bool hasExplicitUseStrict:1;
michael@0 32
michael@0 33 // The (static) bindings of this script need to support dynamic name
michael@0 34 // read/write access. Here, 'dynamic' means dynamic dictionary lookup on
michael@0 35 // the scope chain for a dynamic set of keys. The primary examples are:
michael@0 36 // - direct eval
michael@0 37 // - function::
michael@0 38 // - with
michael@0 39 // since both effectively allow any name to be accessed. Non-examples are:
michael@0 40 // - upvars of nested functions
michael@0 41 // - function statement
michael@0 42 // since the set of assigned name is known dynamically. 'with' could be in
michael@0 43 // the non-example category, provided the set of all free variables within
michael@0 44 // the with block was noted. However, we do not optimize 'with' so, for
michael@0 45 // simplicity, 'with' is treated like eval.
michael@0 46 //
michael@0 47 // Note: access through the arguments object is not considered dynamic
michael@0 48 // binding access since it does not go through the normal name lookup
michael@0 49 // mechanism. This is debatable and could be changed (although care must be
michael@0 50 // taken not to turn off the whole 'arguments' optimization). To answer the
michael@0 51 // more general "is this argument aliased" question, script->needsArgsObj
michael@0 52 // should be tested (see JSScript::argIsAlised).
michael@0 53 //
michael@0 54 bool bindingsAccessedDynamically:1;
michael@0 55
michael@0 56 // Whether this script, or any of its inner scripts contains a debugger
michael@0 57 // statement which could potentially read or write anywhere along the
michael@0 58 // scope chain.
michael@0 59 bool hasDebuggerStatement:1;
michael@0 60
michael@0 61 public:
michael@0 62 AnyContextFlags()
michael@0 63 : hasExplicitUseStrict(false),
michael@0 64 bindingsAccessedDynamically(false),
michael@0 65 hasDebuggerStatement(false)
michael@0 66 { }
michael@0 67 };
michael@0 68
michael@0 69 class FunctionContextFlags
michael@0 70 {
michael@0 71 // This class's data is all private and so only visible to these friends.
michael@0 72 friend class FunctionBox;
michael@0 73
michael@0 74 // The function or a function that encloses it may define new local names
michael@0 75 // at runtime through means other than calling eval.
michael@0 76 bool mightAliasLocals:1;
michael@0 77
michael@0 78 // This function does something that can extend the set of bindings in its
michael@0 79 // call objects --- it does a direct eval in non-strict code, or includes a
michael@0 80 // function statement (as opposed to a function definition).
michael@0 81 //
michael@0 82 // This flag is *not* inherited by enclosed or enclosing functions; it
michael@0 83 // applies only to the function in whose flags it appears.
michael@0 84 //
michael@0 85 bool hasExtensibleScope:1;
michael@0 86
michael@0 87 // This function refers directly to its name in a way which requires the
michael@0 88 // name to be a separate object on the scope chain.
michael@0 89 bool needsDeclEnvObject:1;
michael@0 90
michael@0 91 // Technically, every function has a binding named 'arguments'. Internally,
michael@0 92 // this binding is only added when 'arguments' is mentioned by the function
michael@0 93 // body. This flag indicates whether 'arguments' has been bound either
michael@0 94 // through implicit use:
michael@0 95 // function f() { return arguments }
michael@0 96 // or explicit redeclaration:
michael@0 97 // function f() { var arguments; return arguments }
michael@0 98 //
michael@0 99 // Note 1: overwritten arguments (function() { arguments = 3 }) will cause
michael@0 100 // this flag to be set but otherwise require no special handling:
michael@0 101 // 'arguments' is just a local variable and uses of 'arguments' will just
michael@0 102 // read the local's current slot which may have been assigned. The only
michael@0 103 // special semantics is that the initial value of 'arguments' is the
michael@0 104 // arguments object (not undefined, like normal locals).
michael@0 105 //
michael@0 106 // Note 2: if 'arguments' is bound as a formal parameter, there will be an
michael@0 107 // 'arguments' in Bindings, but, as the "LOCAL" in the name indicates, this
michael@0 108 // flag will not be set. This is because, as a formal, 'arguments' will
michael@0 109 // have no special semantics: the initial value is unconditionally the
michael@0 110 // actual argument (or undefined if nactual < nformal).
michael@0 111 //
michael@0 112 bool argumentsHasLocalBinding:1;
michael@0 113
michael@0 114 // In many cases where 'arguments' has a local binding (as described above)
michael@0 115 // we do not need to actually create an arguments object in the function
michael@0 116 // prologue: instead we can analyze how 'arguments' is used (using the
michael@0 117 // simple dataflow analysis in analyzeSSA) to determine that uses of
michael@0 118 // 'arguments' can just read from the stack frame directly. However, the
michael@0 119 // dataflow analysis only looks at how JSOP_ARGUMENTS is used, so it will
michael@0 120 // be unsound in several cases. The frontend filters out such cases by
michael@0 121 // setting this flag which eagerly sets script->needsArgsObj to true.
michael@0 122 //
michael@0 123 bool definitelyNeedsArgsObj:1;
michael@0 124
michael@0 125 public:
michael@0 126 FunctionContextFlags()
michael@0 127 : mightAliasLocals(false),
michael@0 128 hasExtensibleScope(false),
michael@0 129 needsDeclEnvObject(false),
michael@0 130 argumentsHasLocalBinding(false),
michael@0 131 definitelyNeedsArgsObj(false)
michael@0 132 { }
michael@0 133 };
michael@0 134
michael@0 135 class GlobalSharedContext;
michael@0 136
michael@0 137 // List of directives that may be encountered in a Directive Prologue (ES5 15.1).
michael@0 138 class Directives
michael@0 139 {
michael@0 140 bool strict_;
michael@0 141 bool asmJS_;
michael@0 142
michael@0 143 public:
michael@0 144 explicit Directives(bool strict) : strict_(strict), asmJS_(false) {}
michael@0 145 template <typename ParseHandler> explicit Directives(ParseContext<ParseHandler> *parent);
michael@0 146
michael@0 147 void setStrict() { strict_ = true; }
michael@0 148 bool strict() const { return strict_; }
michael@0 149
michael@0 150 void setAsmJS() { asmJS_ = true; }
michael@0 151 bool asmJS() const { return asmJS_; }
michael@0 152
michael@0 153 Directives &operator=(Directives rhs) {
michael@0 154 strict_ = rhs.strict_;
michael@0 155 asmJS_ = rhs.asmJS_;
michael@0 156 return *this;
michael@0 157 }
michael@0 158 bool operator==(const Directives &rhs) const {
michael@0 159 return strict_ == rhs.strict_ && asmJS_ == rhs.asmJS_;
michael@0 160 }
michael@0 161 bool operator!=(const Directives &rhs) const {
michael@0 162 return !(*this == rhs);
michael@0 163 }
michael@0 164 };
michael@0 165
michael@0 166 /*
michael@0 167 * The struct SharedContext is part of the current parser context (see
michael@0 168 * ParseContext). It stores information that is reused between the parser and
michael@0 169 * the bytecode emitter. Note however, that this information is not shared
michael@0 170 * between the two; they simply reuse the same data structure.
michael@0 171 */
michael@0 172 class SharedContext
michael@0 173 {
michael@0 174 public:
michael@0 175 ExclusiveContext *const context;
michael@0 176 AnyContextFlags anyCxFlags;
michael@0 177 bool strict;
michael@0 178 bool extraWarnings;
michael@0 179
michael@0 180 // If it's function code, funbox must be non-nullptr and scopeChain must be
michael@0 181 // nullptr. If it's global code, funbox must be nullptr.
michael@0 182 SharedContext(ExclusiveContext *cx, Directives directives, bool extraWarnings)
michael@0 183 : context(cx),
michael@0 184 anyCxFlags(),
michael@0 185 strict(directives.strict()),
michael@0 186 extraWarnings(extraWarnings)
michael@0 187 {}
michael@0 188
michael@0 189 virtual ObjectBox *toObjectBox() = 0;
michael@0 190 inline bool isGlobalSharedContext() { return toObjectBox() == nullptr; }
michael@0 191 inline bool isFunctionBox() { return toObjectBox() && toObjectBox()->isFunctionBox(); }
michael@0 192 inline GlobalSharedContext *asGlobalSharedContext();
michael@0 193 inline FunctionBox *asFunctionBox();
michael@0 194
michael@0 195 bool hasExplicitUseStrict() const { return anyCxFlags.hasExplicitUseStrict; }
michael@0 196 bool bindingsAccessedDynamically() const { return anyCxFlags.bindingsAccessedDynamically; }
michael@0 197 bool hasDebuggerStatement() const { return anyCxFlags.hasDebuggerStatement; }
michael@0 198
michael@0 199 void setExplicitUseStrict() { anyCxFlags.hasExplicitUseStrict = true; }
michael@0 200 void setBindingsAccessedDynamically() { anyCxFlags.bindingsAccessedDynamically = true; }
michael@0 201 void setHasDebuggerStatement() { anyCxFlags.hasDebuggerStatement = true; }
michael@0 202
michael@0 203 inline bool allLocalsAliased();
michael@0 204
michael@0 205 // JSOPTION_EXTRA_WARNINGS warnings or strict mode errors.
michael@0 206 bool needStrictChecks() {
michael@0 207 return strict || extraWarnings;
michael@0 208 }
michael@0 209 };
michael@0 210
michael@0 211 class GlobalSharedContext : public SharedContext
michael@0 212 {
michael@0 213 private:
michael@0 214 const RootedObject scopeChain_; /* scope chain object for the script */
michael@0 215
michael@0 216 public:
michael@0 217 GlobalSharedContext(ExclusiveContext *cx, JSObject *scopeChain,
michael@0 218 Directives directives, bool extraWarnings)
michael@0 219 : SharedContext(cx, directives, extraWarnings),
michael@0 220 scopeChain_(cx, scopeChain)
michael@0 221 {}
michael@0 222
michael@0 223 ObjectBox *toObjectBox() { return nullptr; }
michael@0 224 JSObject *scopeChain() const { return scopeChain_; }
michael@0 225 };
michael@0 226
michael@0 227 inline GlobalSharedContext *
michael@0 228 SharedContext::asGlobalSharedContext()
michael@0 229 {
michael@0 230 JS_ASSERT(isGlobalSharedContext());
michael@0 231 return static_cast<GlobalSharedContext*>(this);
michael@0 232 }
michael@0 233
michael@0 234 class FunctionBox : public ObjectBox, public SharedContext
michael@0 235 {
michael@0 236 public:
michael@0 237 Bindings bindings; /* bindings for this function */
michael@0 238 uint32_t bufStart;
michael@0 239 uint32_t bufEnd;
michael@0 240 uint32_t startLine;
michael@0 241 uint32_t startColumn;
michael@0 242 uint16_t length;
michael@0 243
michael@0 244 uint8_t generatorKindBits_; /* The GeneratorKind of this function. */
michael@0 245 bool inWith:1; /* some enclosing scope is a with-statement */
michael@0 246 bool inGenexpLambda:1; /* lambda from generator expression */
michael@0 247 bool hasDestructuringArgs:1; /* arguments list contains destructuring expression */
michael@0 248 bool useAsm:1; /* function contains "use asm" directive */
michael@0 249 bool insideUseAsm:1; /* nested function of function of "use asm" directive */
michael@0 250
michael@0 251 // Fields for use in heuristics.
michael@0 252 bool usesArguments:1; /* contains a free use of 'arguments' */
michael@0 253 bool usesApply:1; /* contains an f.apply() call */
michael@0 254
michael@0 255 FunctionContextFlags funCxFlags;
michael@0 256
michael@0 257 template <typename ParseHandler>
michael@0 258 FunctionBox(ExclusiveContext *cx, ObjectBox* traceListHead, JSFunction *fun,
michael@0 259 ParseContext<ParseHandler> *pc, Directives directives,
michael@0 260 bool extraWarnings, GeneratorKind generatorKind);
michael@0 261
michael@0 262 ObjectBox *toObjectBox() { return this; }
michael@0 263 JSFunction *function() const { return &object->as<JSFunction>(); }
michael@0 264
michael@0 265 GeneratorKind generatorKind() const { return GeneratorKindFromBits(generatorKindBits_); }
michael@0 266 bool isGenerator() const { return generatorKind() != NotGenerator; }
michael@0 267 bool isLegacyGenerator() const { return generatorKind() == LegacyGenerator; }
michael@0 268 bool isStarGenerator() const { return generatorKind() == StarGenerator; }
michael@0 269
michael@0 270 void setGeneratorKind(GeneratorKind kind) {
michael@0 271 // A generator kind can be set at initialization, or when "yield" is
michael@0 272 // first seen. In both cases the transition can only happen from
michael@0 273 // NotGenerator.
michael@0 274 JS_ASSERT(!isGenerator());
michael@0 275 generatorKindBits_ = GeneratorKindAsBits(kind);
michael@0 276 }
michael@0 277
michael@0 278 bool mightAliasLocals() const { return funCxFlags.mightAliasLocals; }
michael@0 279 bool hasExtensibleScope() const { return funCxFlags.hasExtensibleScope; }
michael@0 280 bool needsDeclEnvObject() const { return funCxFlags.needsDeclEnvObject; }
michael@0 281 bool argumentsHasLocalBinding() const { return funCxFlags.argumentsHasLocalBinding; }
michael@0 282 bool definitelyNeedsArgsObj() const { return funCxFlags.definitelyNeedsArgsObj; }
michael@0 283
michael@0 284 void setMightAliasLocals() { funCxFlags.mightAliasLocals = true; }
michael@0 285 void setHasExtensibleScope() { funCxFlags.hasExtensibleScope = true; }
michael@0 286 void setNeedsDeclEnvObject() { funCxFlags.needsDeclEnvObject = true; }
michael@0 287 void setArgumentsHasLocalBinding() { funCxFlags.argumentsHasLocalBinding = true; }
michael@0 288 void setDefinitelyNeedsArgsObj() { JS_ASSERT(funCxFlags.argumentsHasLocalBinding);
michael@0 289 funCxFlags.definitelyNeedsArgsObj = true; }
michael@0 290
michael@0 291 bool hasDefaults() const {
michael@0 292 return length != function()->nargs() - function()->hasRest();
michael@0 293 }
michael@0 294
michael@0 295 // Return whether this function has either specified "use asm" or is
michael@0 296 // (transitively) nested inside a function that has.
michael@0 297 bool useAsmOrInsideUseAsm() const {
michael@0 298 return useAsm || insideUseAsm;
michael@0 299 }
michael@0 300
michael@0 301 void setStart(const TokenStream &tokenStream) {
michael@0 302 bufStart = tokenStream.currentToken().pos.begin;
michael@0 303 startLine = tokenStream.getLineno();
michael@0 304 startColumn = tokenStream.getColumn();
michael@0 305 }
michael@0 306
michael@0 307 bool isHeavyweight()
michael@0 308 {
michael@0 309 // Note: this should be kept in sync with JSFunction::isHeavyweight().
michael@0 310 return bindings.hasAnyAliasedBindings() ||
michael@0 311 hasExtensibleScope() ||
michael@0 312 needsDeclEnvObject() ||
michael@0 313 isGenerator();
michael@0 314 }
michael@0 315 };
michael@0 316
michael@0 317 inline FunctionBox *
michael@0 318 SharedContext::asFunctionBox()
michael@0 319 {
michael@0 320 JS_ASSERT(isFunctionBox());
michael@0 321 return static_cast<FunctionBox*>(this);
michael@0 322 }
michael@0 323
michael@0 324 // In generators, we treat all locals as aliased so that they get stored on the
michael@0 325 // heap. This way there is less information to copy off the stack when
michael@0 326 // suspending, and back on when resuming. It also avoids the need to create and
michael@0 327 // invalidate DebugScope proxies for unaliased locals in a generator frame, as
michael@0 328 // the generator frame will be copied out to the heap and released only by GC.
michael@0 329 inline bool
michael@0 330 SharedContext::allLocalsAliased()
michael@0 331 {
michael@0 332 return bindingsAccessedDynamically() || (isFunctionBox() && asFunctionBox()->isGenerator());
michael@0 333 }
michael@0 334
michael@0 335
michael@0 336 /*
michael@0 337 * NB: If you add a new type of statement that is a scope, add it between
michael@0 338 * STMT_WITH and STMT_CATCH, or you will break StmtInfoBase::linksScope. If you
michael@0 339 * add a non-looping statement type, add it before STMT_DO_LOOP or you will
michael@0 340 * break StmtInfoBase::isLoop().
michael@0 341 *
michael@0 342 * Also remember to keep the statementName array in BytecodeEmitter.cpp in
michael@0 343 * sync.
michael@0 344 */
michael@0 345 enum StmtType {
michael@0 346 STMT_LABEL, /* labeled statement: L: s */
michael@0 347 STMT_IF, /* if (then) statement */
michael@0 348 STMT_ELSE, /* else clause of if statement */
michael@0 349 STMT_SEQ, /* synthetic sequence of statements */
michael@0 350 STMT_BLOCK, /* compound statement: { s1[;... sN] } */
michael@0 351 STMT_SWITCH, /* switch statement */
michael@0 352 STMT_WITH, /* with statement */
michael@0 353 STMT_CATCH, /* catch block */
michael@0 354 STMT_TRY, /* try block */
michael@0 355 STMT_FINALLY, /* finally block */
michael@0 356 STMT_SUBROUTINE, /* gosub-target subroutine body */
michael@0 357 STMT_DO_LOOP, /* do/while loop statement */
michael@0 358 STMT_FOR_LOOP, /* for loop statement */
michael@0 359 STMT_FOR_IN_LOOP, /* for/in loop statement */
michael@0 360 STMT_FOR_OF_LOOP, /* for/of loop statement */
michael@0 361 STMT_WHILE_LOOP, /* while loop statement */
michael@0 362 STMT_LIMIT
michael@0 363 };
michael@0 364
michael@0 365 /*
michael@0 366 * A comment on the encoding of the js::StmtType enum and StmtInfoBase
michael@0 367 * type-testing methods:
michael@0 368 *
michael@0 369 * StmtInfoBase::maybeScope() tells whether a statement type is always, or may
michael@0 370 * become, a lexical scope. It therefore includes block and switch (the two
michael@0 371 * low-numbered "maybe" scope types) and excludes with (with has dynamic scope
michael@0 372 * pending the "reformed with" in ES4/JS2). It includes all try-catch-finally
michael@0 373 * types, which are high-numbered maybe-scope types.
michael@0 374 *
michael@0 375 * StmtInfoBase::linksScope() tells whether a js::StmtInfo{PC,BCE} of the given
michael@0 376 * type eagerly links to other scoping statement info records. It excludes the
michael@0 377 * two early "maybe" types, block and switch, as well as the try and both
michael@0 378 * finally types, since try and the other trailing maybe-scope types don't need
michael@0 379 * block scope unless they contain let declarations.
michael@0 380 *
michael@0 381 * We treat WITH as a static scope because it prevents lexical binding from
michael@0 382 * continuing further up the static scope chain. With the lost "reformed with"
michael@0 383 * proposal for ES4, we would be able to model it statically, too.
michael@0 384 */
michael@0 385
michael@0 386 // StmtInfoPC is used by the Parser. StmtInfoBCE is used by the
michael@0 387 // BytecodeEmitter. The two types have some overlap, encapsulated by
michael@0 388 // StmtInfoBase. Several functions below (e.g. PushStatement) are templated to
michael@0 389 // work with both types.
michael@0 390
michael@0 391 struct StmtInfoBase {
michael@0 392 // Statement type (StmtType).
michael@0 393 uint16_t type;
michael@0 394
michael@0 395 // True if type is STMT_BLOCK, STMT_TRY, STMT_SWITCH, or STMT_FINALLY and
michael@0 396 // the block contains at least one let-declaration, or if type is
michael@0 397 // STMT_CATCH.
michael@0 398 bool isBlockScope:1;
michael@0 399
michael@0 400 // True if isBlockScope or type == STMT_WITH.
michael@0 401 bool isNestedScope:1;
michael@0 402
michael@0 403 // for (let ...) induced block scope
michael@0 404 bool isForLetBlock:1;
michael@0 405
michael@0 406 // Block label.
michael@0 407 RootedAtom label;
michael@0 408
michael@0 409 // Compile-time scope chain node for this scope. Only set if
michael@0 410 // isNestedScope.
michael@0 411 Rooted<NestedScopeObject *> staticScope;
michael@0 412
michael@0 413 StmtInfoBase(ExclusiveContext *cx)
michael@0 414 : isBlockScope(false), isNestedScope(false), isForLetBlock(false),
michael@0 415 label(cx), staticScope(cx)
michael@0 416 {}
michael@0 417
michael@0 418 bool maybeScope() const {
michael@0 419 return STMT_BLOCK <= type && type <= STMT_SUBROUTINE && type != STMT_WITH;
michael@0 420 }
michael@0 421
michael@0 422 bool linksScope() const {
michael@0 423 return isNestedScope;
michael@0 424 }
michael@0 425
michael@0 426 StaticBlockObject& staticBlock() const {
michael@0 427 JS_ASSERT(isNestedScope);
michael@0 428 JS_ASSERT(isBlockScope);
michael@0 429 return staticScope->as<StaticBlockObject>();
michael@0 430 }
michael@0 431
michael@0 432 bool isLoop() const {
michael@0 433 return type >= STMT_DO_LOOP;
michael@0 434 }
michael@0 435
michael@0 436 bool isTrying() const {
michael@0 437 return STMT_TRY <= type && type <= STMT_SUBROUTINE;
michael@0 438 }
michael@0 439 };
michael@0 440
michael@0 441 // Push the C-stack-allocated struct at stmt onto the StmtInfoPC stack.
michael@0 442 template <class ContextT>
michael@0 443 void
michael@0 444 PushStatement(ContextT *ct, typename ContextT::StmtInfo *stmt, StmtType type)
michael@0 445 {
michael@0 446 stmt->type = type;
michael@0 447 stmt->isBlockScope = false;
michael@0 448 stmt->isNestedScope = false;
michael@0 449 stmt->isForLetBlock = false;
michael@0 450 stmt->label = nullptr;
michael@0 451 stmt->staticScope = nullptr;
michael@0 452 stmt->down = ct->topStmt;
michael@0 453 ct->topStmt = stmt;
michael@0 454 if (stmt->linksScope()) {
michael@0 455 stmt->downScope = ct->topScopeStmt;
michael@0 456 ct->topScopeStmt = stmt;
michael@0 457 } else {
michael@0 458 stmt->downScope = nullptr;
michael@0 459 }
michael@0 460 }
michael@0 461
michael@0 462 template <class ContextT>
michael@0 463 void
michael@0 464 FinishPushNestedScope(ContextT *ct, typename ContextT::StmtInfo *stmt, NestedScopeObject &staticScope)
michael@0 465 {
michael@0 466 stmt->isNestedScope = true;
michael@0 467 stmt->downScope = ct->topScopeStmt;
michael@0 468 ct->topScopeStmt = stmt;
michael@0 469 ct->staticScope = &staticScope;
michael@0 470 stmt->staticScope = &staticScope;
michael@0 471 }
michael@0 472
michael@0 473 // Pop pc->topStmt. If the top StmtInfoPC struct is not stack-allocated, it
michael@0 474 // is up to the caller to free it. The dummy argument is just to make the
michael@0 475 // template matching work.
michael@0 476 template <class ContextT>
michael@0 477 void
michael@0 478 FinishPopStatement(ContextT *ct)
michael@0 479 {
michael@0 480 typename ContextT::StmtInfo *stmt = ct->topStmt;
michael@0 481 ct->topStmt = stmt->down;
michael@0 482 if (stmt->linksScope()) {
michael@0 483 ct->topScopeStmt = stmt->downScope;
michael@0 484 if (stmt->isNestedScope) {
michael@0 485 JS_ASSERT(stmt->staticScope);
michael@0 486 ct->staticScope = stmt->staticScope->enclosingNestedScope();
michael@0 487 }
michael@0 488 }
michael@0 489 }
michael@0 490
michael@0 491 /*
michael@0 492 * Find a lexically scoped variable (one declared by let, catch, or an array
michael@0 493 * comprehension) named by atom, looking in sc's compile-time scopes.
michael@0 494 *
michael@0 495 * If a WITH statement is reached along the scope stack, return its statement
michael@0 496 * info record, so callers can tell that atom is ambiguous. If slotp is not
michael@0 497 * null, then if atom is found, set *slotp to its stack slot, otherwise to -1.
michael@0 498 * This means that if slotp is not null, all the block objects on the lexical
michael@0 499 * scope chain must have had their depth slots computed by the code generator,
michael@0 500 * so the caller must be under EmitTree.
michael@0 501 *
michael@0 502 * In any event, directly return the statement info record in which atom was
michael@0 503 * found. Otherwise return null.
michael@0 504 */
michael@0 505 template <class ContextT>
michael@0 506 typename ContextT::StmtInfo *
michael@0 507 LexicalLookup(ContextT *ct, HandleAtom atom, int *slotp, typename ContextT::StmtInfo *stmt);
michael@0 508
michael@0 509 } // namespace frontend
michael@0 510
michael@0 511 } // namespace js
michael@0 512
michael@0 513 #endif /* frontend_SharedContext_h */

mercurial