2 * Copyright (C) 2014, 2015 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include "FTLOperations.h"
31 #include "ClonedArguments.h"
32 #include "DirectArguments.h"
33 #include "JSCInlines.h"
34 #include "JSLexicalEnvironment.h"
36 namespace JSC
{ namespace FTL
{
38 using namespace JSC::DFG
;
40 extern "C" JSCell
* JIT_OPERATION
operationNewObjectWithButterfly(ExecState
* exec
, Structure
* structure
)
43 NativeCallFrameTracer
tracer(&vm
, exec
);
45 Butterfly
* butterfly
= Butterfly::create(
46 vm
, nullptr, 0, structure
->outOfLineCapacity(), false, IndexingHeader(), 0);
48 return JSFinalObject::create(exec
, structure
, butterfly
);
51 extern "C" JSCell
* JIT_OPERATION
operationMaterializeObjectInOSR(
52 ExecState
* exec
, ExitTimeObjectMaterialization
* materialization
, EncodedJSValue
* values
)
55 CodeBlock
* codeBlock
= exec
->codeBlock();
57 // We cannot GC. We've got pointers in evil places.
58 DeferGCForAWhile
deferGC(vm
.heap
);
60 switch (materialization
->type()) {
61 case PhantomNewObject
: {
62 // First figure out what the structure is.
63 Structure
* structure
= nullptr;
64 for (unsigned i
= materialization
->properties().size(); i
--;) {
65 const ExitPropertyValue
& property
= materialization
->properties()[i
];
66 if (property
.location() != PromotedLocationDescriptor(StructurePLoc
))
69 structure
= jsCast
<Structure
*>(JSValue::decode(values
[i
]));
72 RELEASE_ASSERT(structure
);
74 // Let's create that object!
75 JSFinalObject
* result
= JSFinalObject::create(vm
, structure
);
77 // Now figure out what the heck to populate the object with. Use getPropertiesConcurrently()
78 // because that happens to be lower-level and more convenient. It doesn't change the
79 // materialization of the property table. We want to have minimal visible effects on the
80 // system. Also, don't mind that this is O(n^2). It doesn't matter. We only get here from OSR
82 for (PropertyMapEntry entry
: structure
->getPropertiesConcurrently()) {
83 for (unsigned i
= materialization
->properties().size(); i
--;) {
84 const ExitPropertyValue
& property
= materialization
->properties()[i
];
85 if (property
.location().kind() != NamedPropertyPLoc
)
87 if (codeBlock
->identifier(property
.location().info()).impl() != entry
.key
)
90 result
->putDirect(vm
, entry
.offset
, JSValue::decode(values
[i
]));
97 case PhantomNewFunction
: {
98 // Figure out what the executable and activation are
99 FunctionExecutable
* executable
= nullptr;
100 JSScope
* activation
= nullptr;
101 for (unsigned i
= materialization
->properties().size(); i
--;) {
102 const ExitPropertyValue
& property
= materialization
->properties()[i
];
103 if (property
.location() == PromotedLocationDescriptor(FunctionExecutablePLoc
))
104 executable
= jsCast
<FunctionExecutable
*>(JSValue::decode(values
[i
]));
105 if (property
.location() == PromotedLocationDescriptor(FunctionActivationPLoc
))
106 activation
= jsCast
<JSScope
*>(JSValue::decode(values
[i
]));
108 RELEASE_ASSERT(executable
&& activation
);
110 JSFunction
* result
= JSFunction::createWithInvalidatedReallocationWatchpoint(vm
, executable
, activation
);
115 case PhantomCreateActivation
: {
116 // Figure out where the scope is
117 JSScope
* scope
= nullptr;
118 SymbolTable
* table
= nullptr;
119 for (unsigned i
= materialization
->properties().size(); i
--;) {
120 const ExitPropertyValue
& property
= materialization
->properties()[i
];
121 if (property
.location() == PromotedLocationDescriptor(ActivationScopePLoc
))
122 scope
= jsCast
<JSScope
*>(JSValue::decode(values
[i
]));
123 else if (property
.location() == PromotedLocationDescriptor(ActivationSymbolTablePLoc
))
124 table
= jsCast
<SymbolTable
*>(JSValue::decode(values
[i
]));
126 RELEASE_ASSERT(scope
);
127 RELEASE_ASSERT(table
);
129 CodeBlock
* codeBlock
= baselineCodeBlockForOriginAndBaselineCodeBlock(
130 materialization
->origin(), exec
->codeBlock());
131 Structure
* structure
= codeBlock
->globalObject()->activationStructure();
133 JSLexicalEnvironment
* result
= JSLexicalEnvironment::create(vm
, structure
, scope
, table
);
135 RELEASE_ASSERT(materialization
->properties().size() - 2 == table
->scopeSize());
136 // Figure out what to populate the activation with
137 for (unsigned i
= materialization
->properties().size(); i
--;) {
138 const ExitPropertyValue
& property
= materialization
->properties()[i
];
139 if (property
.location().kind() != ClosureVarPLoc
)
142 result
->variableAt(ScopeOffset(property
.location().info())).set(exec
->vm(), result
, JSValue::decode(values
[i
]));
145 if (validationEnabled()) {
146 // Validate to make sure every slot in the scope has one value.
147 ConcurrentJITLocker
locker(table
->m_lock
);
148 for (auto iter
= table
->begin(locker
), end
= table
->end(locker
); iter
!= end
; ++iter
) {
150 for (unsigned i
= materialization
->properties().size(); i
--;) {
151 const ExitPropertyValue
& property
= materialization
->properties()[i
];
152 if (property
.location().kind() != ClosureVarPLoc
)
154 if (ScopeOffset(property
.location().info()) == iter
->value
.scopeOffset()) {
159 ASSERT_UNUSED(found
, found
);
161 unsigned numberOfClosureVarPloc
= 0;
162 for (unsigned i
= materialization
->properties().size(); i
--;) {
163 const ExitPropertyValue
& property
= materialization
->properties()[i
];
164 if (property
.location().kind() == ClosureVarPLoc
)
165 numberOfClosureVarPloc
++;
167 ASSERT(numberOfClosureVarPloc
== table
->scopeSize());
173 case PhantomDirectArguments
:
174 case PhantomClonedArguments
: {
175 if (!materialization
->origin().inlineCallFrame
) {
176 switch (materialization
->type()) {
177 case PhantomDirectArguments
:
178 return DirectArguments::createByCopying(exec
);
179 case PhantomClonedArguments
:
180 return ClonedArguments::createWithMachineFrame(exec
, exec
, ArgumentsMode::Cloned
);
182 RELEASE_ASSERT_NOT_REACHED();
187 // First figure out the argument count. If there isn't one then we represent the machine frame.
188 unsigned argumentCount
= 0;
189 if (materialization
->origin().inlineCallFrame
->isVarargs()) {
190 for (unsigned i
= materialization
->properties().size(); i
--;) {
191 const ExitPropertyValue
& property
= materialization
->properties()[i
];
192 if (property
.location() != PromotedLocationDescriptor(ArgumentCountPLoc
))
195 argumentCount
= JSValue::decode(values
[i
]).asUInt32();
196 RELEASE_ASSERT(argumentCount
);
199 RELEASE_ASSERT(argumentCount
);
201 argumentCount
= materialization
->origin().inlineCallFrame
->arguments
.size();
203 JSFunction
* callee
= nullptr;
204 if (materialization
->origin().inlineCallFrame
->isClosureCall
) {
205 for (unsigned i
= materialization
->properties().size(); i
--;) {
206 const ExitPropertyValue
& property
= materialization
->properties()[i
];
207 if (property
.location() != PromotedLocationDescriptor(ArgumentsCalleePLoc
))
210 callee
= jsCast
<JSFunction
*>(JSValue::decode(values
[i
]));
214 callee
= materialization
->origin().inlineCallFrame
->calleeConstant();
215 RELEASE_ASSERT(callee
);
217 CodeBlock
* codeBlock
= baselineCodeBlockForOriginAndBaselineCodeBlock(
218 materialization
->origin(), exec
->codeBlock());
220 // We have an inline frame and we have all of the data we need to recreate it.
221 switch (materialization
->type()) {
222 case PhantomDirectArguments
: {
223 unsigned length
= argumentCount
- 1;
224 unsigned capacity
= std::max(length
, static_cast<unsigned>(codeBlock
->numParameters() - 1));
225 DirectArguments
* result
= DirectArguments::create(
226 vm
, codeBlock
->globalObject()->directArgumentsStructure(), length
, capacity
);
227 result
->callee().set(vm
, result
, callee
);
228 for (unsigned i
= materialization
->properties().size(); i
--;) {
229 const ExitPropertyValue
& property
= materialization
->properties()[i
];
230 if (property
.location().kind() != ArgumentPLoc
)
233 unsigned index
= property
.location().info();
234 if (index
>= capacity
)
237 // We don't want to use setIndexQuickly(), since that's only for the passed-in
238 // arguments but sometimes the number of named arguments is greater. For
241 // function foo(a, b, c) { ... }
244 // setIndexQuickly() would fail for indices 0, 1, 2 - but we need to recover
246 result
->argument(DirectArgumentsOffset(index
)).set(
247 vm
, result
, JSValue::decode(values
[i
]));
251 case PhantomClonedArguments
: {
252 unsigned length
= argumentCount
- 1;
253 ClonedArguments
* result
= ClonedArguments::createEmpty(
254 vm
, codeBlock
->globalObject()->outOfBandArgumentsStructure(), callee
);
256 for (unsigned i
= materialization
->properties().size(); i
--;) {
257 const ExitPropertyValue
& property
= materialization
->properties()[i
];
258 if (property
.location().kind() != ArgumentPLoc
)
261 unsigned index
= property
.location().info();
264 result
->putDirectIndex(exec
, index
, JSValue::decode(values
[i
]));
267 result
->putDirect(vm
, vm
.propertyNames
->length
, jsNumber(length
));
271 RELEASE_ASSERT_NOT_REACHED();
277 RELEASE_ASSERT_NOT_REACHED();
282 } } // namespace JSC::FTL
284 #endif // ENABLE(FTL_JIT)