1/*
2 * Copyright (C) 2008-2019 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of Apple Inc. ("Apple") nor the names of
14 * its contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#pragma once
30
31#include "CodeBlock.h"
32#include "JSSymbolTableObject.h"
33#include "SymbolTable.h"
34
35namespace JSC {
36
37class LLIntOffsetsExtractor;
38
39class JSLexicalEnvironment : public JSSymbolTableObject {
40 friend class JIT;
41 friend class LLIntOffsetsExtractor;
42public:
43 template<typename CellType, SubspaceAccess>
44 static CompleteSubspace* subspaceFor(VM& vm)
45 {
46 static_assert(!CellType::needsDestruction, "");
47 return &vm.variableSizedCellSpace;
48 }
49
50 using Base = JSSymbolTableObject;
51 static constexpr unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetPropertyNames;
52
53 WriteBarrierBase<Unknown>* variables()
54 {
55 return bitwise_cast<WriteBarrierBase<Unknown>*>(bitwise_cast<char*>(this) + offsetOfVariables());
56 }
57
58 bool isValidScopeOffset(ScopeOffset offset)
59 {
60 return !!offset && offset.offset() < symbolTable()->scopeSize();
61 }
62
63 WriteBarrierBase<Unknown>& variableAt(ScopeOffset offset)
64 {
65 ASSERT(isValidScopeOffset(offset));
66 return variables()[offset.offset()];
67 }
68
69 static size_t offsetOfVariables()
70 {
71 return WTF::roundUpToMultipleOf<sizeof(WriteBarrier<Unknown>)>(sizeof(JSLexicalEnvironment));
72 }
73
74 static size_t offsetOfVariable(ScopeOffset offset)
75 {
76 Checked<size_t> scopeOffset = offset.offset();
77 return (offsetOfVariables() + scopeOffset * sizeof(WriteBarrier<Unknown>)).unsafeGet();
78 }
79
80 static size_t allocationSizeForScopeSize(Checked<size_t> scopeSize)
81 {
82 return (offsetOfVariables() + scopeSize * sizeof(WriteBarrier<Unknown>)).unsafeGet();
83 }
84
85 static size_t allocationSize(SymbolTable* symbolTable)
86 {
87 return allocationSizeForScopeSize(symbolTable->scopeSize());
88 }
89
90 static JSLexicalEnvironment* create(
91 VM& vm, Structure* structure, JSScope* currentScope, SymbolTable* symbolTable, JSValue initialValue)
92 {
93 JSLexicalEnvironment* result =
94 new (
95 NotNull,
96 allocateCell<JSLexicalEnvironment>(vm.heap, allocationSize(symbolTable)))
97 JSLexicalEnvironment(vm, structure, currentScope, symbolTable);
98 result->finishCreation(vm, initialValue);
99 return result;
100 }
101
102 static JSLexicalEnvironment* create(VM& vm, JSGlobalObject* globalObject, JSScope* currentScope, SymbolTable* symbolTable, JSValue initialValue)
103 {
104 Structure* structure = globalObject->activationStructure();
105 return create(vm, structure, currentScope, symbolTable, initialValue);
106 }
107
108 static bool getOwnPropertySlot(JSObject*, JSGlobalObject*, PropertyName, PropertySlot&);
109 static void getOwnNonIndexPropertyNames(JSObject*, JSGlobalObject*, PropertyNameArray&, EnumerationMode);
110
111 static bool put(JSCell*, JSGlobalObject*, PropertyName, JSValue, PutPropertySlot&);
112
113 static bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName);
114
115 DECLARE_INFO;
116
117 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject) { return Structure::create(vm, globalObject, jsNull(), TypeInfo(LexicalEnvironmentType, StructureFlags), info()); }
118
119protected:
120 JSLexicalEnvironment(VM&, Structure*, JSScope*, SymbolTable*);
121
122 void finishCreationUninitialized(VM& vm)
123 {
124 Base::finishCreation(vm);
125 }
126
127 void finishCreation(VM& vm, JSValue value)
128 {
129 finishCreationUninitialized(vm);
130 ASSERT(value == jsUndefined() || value == jsTDZValue());
131 for (unsigned i = symbolTable()->scopeSize(); i--;) {
132 // Filling this with undefined/TDZEmptyValue is useful because that's what variables start out as.
133 variableAt(ScopeOffset(i)).setStartingValue(value);
134 }
135 }
136
137 static void visitChildren(JSCell*, SlotVisitor&);
138 static void analyzeHeap(JSCell*, HeapAnalyzer&);
139};
140
141inline JSLexicalEnvironment::JSLexicalEnvironment(VM& vm, Structure* structure, JSScope* currentScope, SymbolTable* symbolTable)
142 : Base(vm, structure, currentScope, symbolTable)
143{
144}
145
146} // namespace JSC
147