]>
Commit | Line | Data |
---|---|---|
14957cd0 | 1 | /* |
ed1e77d3 | 2 | * Copyright (C) 2011, 2013-2015 Apple Inc. All rights reserved. |
14957cd0 A |
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 | * 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. | |
12 | * | |
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. | |
24 | */ | |
25 | ||
26 | #include "config.h" | |
27 | #include "DFGOperations.h" | |
28 | ||
93a37866 | 29 | #include "ButterflyInlines.h" |
ed1e77d3 | 30 | #include "ClonedArguments.h" |
14957cd0 | 31 | #include "CodeBlock.h" |
81345200 | 32 | #include "CommonSlowPaths.h" |
93a37866 | 33 | #include "CopiedSpaceInlines.h" |
81345200 A |
34 | #include "DFGDriver.h" |
35 | #include "DFGJITCode.h" | |
6fe7ccc8 | 36 | #include "DFGOSRExit.h" |
93a37866 | 37 | #include "DFGThunks.h" |
81345200 A |
38 | #include "DFGToFTLDeferredCompilationCallback.h" |
39 | #include "DFGToFTLForOSREntryDeferredCompilationCallback.h" | |
40 | #include "DFGWorklist.h" | |
ed1e77d3 | 41 | #include "DirectArguments.h" |
81345200 A |
42 | #include "FTLForOSREntryJITCode.h" |
43 | #include "FTLOSREntry.h" | |
6fe7ccc8 A |
44 | #include "HostCallReturnValue.h" |
45 | #include "GetterSetter.h" | |
14957cd0 | 46 | #include "Interpreter.h" |
93a37866 | 47 | #include "JIT.h" |
6fe7ccc8 | 48 | #include "JITExceptions.h" |
ed1e77d3 A |
49 | #include "JSCInlines.h" |
50 | #include "JSLexicalEnvironment.h" | |
93a37866 | 51 | #include "JSNameScope.h" |
93a37866 | 52 | #include "ObjectConstructor.h" |
81345200 | 53 | #include "Repatch.h" |
ed1e77d3 | 54 | #include "ScopedArguments.h" |
93a37866 | 55 | #include "StringConstructor.h" |
ed1e77d3 A |
56 | #include "Symbol.h" |
57 | #include "TypeProfilerLog.h" | |
81345200 | 58 | #include "TypedArrayInlines.h" |
ed1e77d3 | 59 | #include "VM.h" |
93a37866 A |
60 | #include <wtf/InlineASM.h> |
61 | ||
62 | #if ENABLE(JIT) | |
6fe7ccc8 A |
63 | #if ENABLE(DFG_JIT) |
64 | ||
14957cd0 A |
65 | namespace JSC { namespace DFG { |
66 | ||
81345200 | 67 | template<bool strict, bool direct> |
6fe7ccc8 A |
68 | static inline void putByVal(ExecState* exec, JSValue baseValue, uint32_t index, JSValue value) |
69 | { | |
93a37866 A |
70 | VM& vm = exec->vm(); |
71 | NativeCallFrameTracer tracer(&vm, exec); | |
ed1e77d3 | 72 | ASSERT(isIndex(index)); |
81345200 A |
73 | if (direct) { |
74 | RELEASE_ASSERT(baseValue.isObject()); | |
75 | asObject(baseValue)->putDirectIndex(exec, index, value, 0, strict ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow); | |
76 | return; | |
77 | } | |
93a37866 A |
78 | if (baseValue.isObject()) { |
79 | JSObject* object = asObject(baseValue); | |
80 | if (object->canSetIndexQuickly(index)) { | |
81 | object->setIndexQuickly(vm, index, value); | |
6fe7ccc8 A |
82 | return; |
83 | } | |
84 | ||
81345200 | 85 | object->methodTable(vm)->putByIndex(object, exec, index, value, strict); |
6fe7ccc8 A |
86 | return; |
87 | } | |
88 | ||
89 | baseValue.putByIndex(exec, index, value, strict); | |
90 | } | |
91 | ||
81345200 A |
92 | template<bool strict, bool direct> |
93 | ALWAYS_INLINE static void JIT_OPERATION operationPutByValInternal(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) | |
14957cd0 | 94 | { |
93a37866 A |
95 | VM* vm = &exec->vm(); |
96 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 A |
97 | |
98 | JSValue baseValue = JSValue::decode(encodedBase); | |
99 | JSValue property = JSValue::decode(encodedProperty); | |
100 | JSValue value = JSValue::decode(encodedValue); | |
101 | ||
102 | if (LIKELY(property.isUInt32())) { | |
ed1e77d3 A |
103 | // Despite its name, JSValue::isUInt32 will return true only for positive boxed int32_t; all those values are valid array indices. |
104 | ASSERT(isIndex(property.asUInt32())); | |
81345200 | 105 | putByVal<strict, direct>(exec, baseValue, property.asUInt32(), value); |
6fe7ccc8 A |
106 | return; |
107 | } | |
108 | ||
109 | if (property.isDouble()) { | |
110 | double propertyAsDouble = property.asDouble(); | |
111 | uint32_t propertyAsUInt32 = static_cast<uint32_t>(propertyAsDouble); | |
ed1e77d3 | 112 | if (propertyAsDouble == propertyAsUInt32 && isIndex(propertyAsUInt32)) { |
81345200 | 113 | putByVal<strict, direct>(exec, baseValue, propertyAsUInt32, value); |
6fe7ccc8 A |
114 | return; |
115 | } | |
116 | } | |
117 | ||
ed1e77d3 A |
118 | // Don't put to an object if toString throws an exception. |
119 | auto propertyName = property.toPropertyKey(exec); | |
120 | if (vm->exception()) | |
93a37866 | 121 | return; |
6fe7ccc8 | 122 | |
ed1e77d3 A |
123 | PutPropertySlot slot(baseValue, strict); |
124 | if (direct) { | |
125 | RELEASE_ASSERT(baseValue.isObject()); | |
126 | if (Optional<uint32_t> index = parseIndex(propertyName)) | |
127 | asObject(baseValue)->putDirectIndex(exec, index.value(), value, 0, strict ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow); | |
128 | else | |
129 | asObject(baseValue)->putDirect(*vm, propertyName, value, slot); | |
130 | } else | |
131 | baseValue.put(exec, propertyName, value, slot); | |
81345200 A |
132 | } |
133 | ||
134 | template<typename ViewClass> | |
135 | char* newTypedArrayWithSize(ExecState* exec, Structure* structure, int32_t size) | |
136 | { | |
137 | VM& vm = exec->vm(); | |
138 | NativeCallFrameTracer tracer(&vm, exec); | |
139 | if (size < 0) { | |
ed1e77d3 | 140 | vm.throwException(exec, createRangeError(exec, ASCIILiteral("Requested length is negative"))); |
81345200 A |
141 | return 0; |
142 | } | |
143 | return bitwise_cast<char*>(ViewClass::create(exec, structure, size)); | |
144 | } | |
145 | ||
146 | template<typename ViewClass> | |
147 | char* newTypedArrayWithOneArgument( | |
148 | ExecState* exec, Structure* structure, EncodedJSValue encodedValue) | |
149 | { | |
150 | VM& vm = exec->vm(); | |
151 | NativeCallFrameTracer tracer(&vm, exec); | |
152 | ||
153 | JSValue value = JSValue::decode(encodedValue); | |
154 | ||
155 | if (JSArrayBuffer* jsBuffer = jsDynamicCast<JSArrayBuffer*>(value)) { | |
156 | RefPtr<ArrayBuffer> buffer = jsBuffer->impl(); | |
157 | ||
158 | if (buffer->byteLength() % ViewClass::elementSize) { | |
ed1e77d3 | 159 | vm.throwException(exec, createRangeError(exec, ASCIILiteral("ArrayBuffer length minus the byteOffset is not a multiple of the element size"))); |
81345200 A |
160 | return 0; |
161 | } | |
162 | return bitwise_cast<char*>( | |
163 | ViewClass::create( | |
164 | exec, structure, buffer, 0, buffer->byteLength() / ViewClass::elementSize)); | |
165 | } | |
166 | ||
167 | if (JSObject* object = jsDynamicCast<JSObject*>(value)) { | |
168 | unsigned length = object->get(exec, vm.propertyNames->length).toUInt32(exec); | |
169 | if (exec->hadException()) | |
170 | return 0; | |
171 | ||
172 | ViewClass* result = ViewClass::createUninitialized(exec, structure, length); | |
173 | if (!result) | |
174 | return 0; | |
175 | ||
176 | if (!result->set(exec, object, 0, length)) | |
177 | return 0; | |
178 | ||
179 | return bitwise_cast<char*>(result); | |
180 | } | |
181 | ||
182 | int length; | |
183 | if (value.isInt32()) | |
184 | length = value.asInt32(); | |
185 | else if (!value.isNumber()) { | |
ed1e77d3 | 186 | vm.throwException(exec, createTypeError(exec, ASCIILiteral("Invalid array length argument"))); |
81345200 A |
187 | return 0; |
188 | } else { | |
189 | length = static_cast<int>(value.asNumber()); | |
190 | if (length != value.asNumber()) { | |
ed1e77d3 | 191 | vm.throwException(exec, createTypeError(exec, ASCIILiteral("Invalid array length argument (fractional lengths not allowed)"))); |
81345200 A |
192 | return 0; |
193 | } | |
194 | } | |
195 | ||
196 | if (length < 0) { | |
ed1e77d3 | 197 | vm.throwException(exec, createRangeError(exec, ASCIILiteral("Requested length is negative"))); |
81345200 | 198 | return 0; |
6fe7ccc8 | 199 | } |
81345200 A |
200 | |
201 | return bitwise_cast<char*>(ViewClass::create(exec, structure, length)); | |
6fe7ccc8 A |
202 | } |
203 | ||
204 | extern "C" { | |
205 | ||
81345200 | 206 | EncodedJSValue JIT_OPERATION operationToThis(ExecState* exec, EncodedJSValue encodedOp) |
6fe7ccc8 | 207 | { |
93a37866 A |
208 | VM* vm = &exec->vm(); |
209 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 | 210 | |
81345200 | 211 | return JSValue::encode(JSValue::decode(encodedOp).toThis(exec, NotStrictMode)); |
14957cd0 A |
212 | } |
213 | ||
81345200 | 214 | EncodedJSValue JIT_OPERATION operationToThisStrict(ExecState* exec, EncodedJSValue encodedOp) |
14957cd0 | 215 | { |
93a37866 A |
216 | VM* vm = &exec->vm(); |
217 | NativeCallFrameTracer tracer(vm, exec); | |
218 | ||
81345200 A |
219 | return JSValue::encode(JSValue::decode(encodedOp).toThis(exec, StrictMode)); |
220 | } | |
221 | ||
222 | JSCell* JIT_OPERATION operationCreateThis(ExecState* exec, JSObject* constructor, int32_t inlineCapacity) | |
223 | { | |
224 | VM& vm = exec->vm(); | |
225 | NativeCallFrameTracer tracer(&vm, exec); | |
226 | ||
6fe7ccc8 A |
227 | #if !ASSERT_DISABLED |
228 | ConstructData constructData; | |
81345200 | 229 | ASSERT(jsCast<JSFunction*>(constructor)->methodTable(vm)->getConstructData(jsCast<JSFunction*>(constructor), constructData) == ConstructTypeJS); |
6fe7ccc8 A |
230 | #endif |
231 | ||
ed1e77d3 | 232 | return constructEmptyObject(exec, jsCast<JSFunction*>(constructor)->rareData(exec, inlineCapacity)->allocationProfile()->structure()); |
6fe7ccc8 A |
233 | } |
234 | ||
81345200 | 235 | EncodedJSValue JIT_OPERATION operationValueAdd(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) |
6fe7ccc8 | 236 | { |
93a37866 A |
237 | VM* vm = &exec->vm(); |
238 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 | 239 | |
14957cd0 A |
240 | JSValue op1 = JSValue::decode(encodedOp1); |
241 | JSValue op2 = JSValue::decode(encodedOp2); | |
6fe7ccc8 A |
242 | |
243 | return JSValue::encode(jsAdd(exec, op1, op2)); | |
244 | } | |
14957cd0 | 245 | |
81345200 | 246 | EncodedJSValue JIT_OPERATION operationValueAddNotNumber(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) |
6fe7ccc8 | 247 | { |
93a37866 A |
248 | VM* vm = &exec->vm(); |
249 | NativeCallFrameTracer tracer(vm, exec); | |
14957cd0 | 250 | |
6fe7ccc8 A |
251 | JSValue op1 = JSValue::decode(encodedOp1); |
252 | JSValue op2 = JSValue::decode(encodedOp2); | |
253 | ||
254 | ASSERT(!op1.isNumber() || !op2.isNumber()); | |
255 | ||
256 | if (op1.isString() && !op2.isObject()) | |
257 | return JSValue::encode(jsString(exec, asString(op1), op2.toString(exec))); | |
14957cd0 A |
258 | |
259 | return JSValue::encode(jsAddSlowCase(exec, op1, op2)); | |
260 | } | |
261 | ||
81345200 | 262 | static ALWAYS_INLINE EncodedJSValue getByVal(ExecState* exec, JSCell* base, uint32_t index) |
6fe7ccc8 | 263 | { |
93a37866 A |
264 | VM& vm = exec->vm(); |
265 | NativeCallFrameTracer tracer(&vm, exec); | |
6fe7ccc8 | 266 | |
93a37866 A |
267 | if (base->isObject()) { |
268 | JSObject* object = asObject(base); | |
269 | if (object->canGetIndexQuickly(index)) | |
270 | return JSValue::encode(object->getIndexQuickly(index)); | |
271 | } | |
6fe7ccc8 | 272 | |
6fe7ccc8 A |
273 | if (isJSString(base) && asString(base)->canGetIndex(index)) |
274 | return JSValue::encode(asString(base)->getIndex(exec, index)); | |
275 | ||
276 | return JSValue::encode(JSValue(base).get(exec, index)); | |
277 | } | |
278 | ||
81345200 | 279 | EncodedJSValue JIT_OPERATION operationGetByVal(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty) |
14957cd0 | 280 | { |
81345200 A |
281 | VM& vm = exec->vm(); |
282 | NativeCallFrameTracer tracer(&vm, exec); | |
6fe7ccc8 | 283 | |
14957cd0 A |
284 | JSValue baseValue = JSValue::decode(encodedBase); |
285 | JSValue property = JSValue::decode(encodedProperty); | |
286 | ||
287 | if (LIKELY(baseValue.isCell())) { | |
288 | JSCell* base = baseValue.asCell(); | |
289 | ||
290 | if (property.isUInt32()) { | |
6fe7ccc8 A |
291 | return getByVal(exec, base, property.asUInt32()); |
292 | } else if (property.isDouble()) { | |
293 | double propertyAsDouble = property.asDouble(); | |
294 | uint32_t propertyAsUInt32 = static_cast<uint32_t>(propertyAsDouble); | |
ed1e77d3 | 295 | if (propertyAsUInt32 == propertyAsDouble && isIndex(propertyAsUInt32)) |
6fe7ccc8 A |
296 | return getByVal(exec, base, propertyAsUInt32); |
297 | } else if (property.isString()) { | |
81345200 A |
298 | Structure& structure = *base->structure(vm); |
299 | if (JSCell::canUseFastGetOwnProperty(structure)) { | |
ed1e77d3 A |
300 | if (RefPtr<AtomicStringImpl> existingAtomicString = asString(property)->toExistingAtomicString(exec)) { |
301 | if (JSValue result = base->fastGetOwnProperty(vm, structure, existingAtomicString.get())) | |
302 | return JSValue::encode(result); | |
303 | } | |
81345200 | 304 | } |
6fe7ccc8 A |
305 | } |
306 | } | |
14957cd0 | 307 | |
ed1e77d3 A |
308 | baseValue.requireObjectCoercible(exec); |
309 | if (exec->hadException()) | |
310 | return JSValue::encode(jsUndefined()); | |
311 | auto propertyName = property.toPropertyKey(exec); | |
312 | if (exec->hadException()) | |
313 | return JSValue::encode(jsUndefined()); | |
314 | return JSValue::encode(baseValue.get(exec, propertyName)); | |
6fe7ccc8 | 315 | } |
14957cd0 | 316 | |
81345200 | 317 | EncodedJSValue JIT_OPERATION operationGetByValCell(ExecState* exec, JSCell* base, EncodedJSValue encodedProperty) |
6fe7ccc8 | 318 | { |
81345200 A |
319 | VM& vm = exec->vm(); |
320 | NativeCallFrameTracer tracer(&vm, exec); | |
6fe7ccc8 A |
321 | |
322 | JSValue property = JSValue::decode(encodedProperty); | |
14957cd0 | 323 | |
6fe7ccc8 A |
324 | if (property.isUInt32()) |
325 | return getByVal(exec, base, property.asUInt32()); | |
326 | if (property.isDouble()) { | |
327 | double propertyAsDouble = property.asDouble(); | |
328 | uint32_t propertyAsUInt32 = static_cast<uint32_t>(propertyAsDouble); | |
329 | if (propertyAsUInt32 == propertyAsDouble) | |
330 | return getByVal(exec, base, propertyAsUInt32); | |
331 | } else if (property.isString()) { | |
81345200 A |
332 | Structure& structure = *base->structure(vm); |
333 | if (JSCell::canUseFastGetOwnProperty(structure)) { | |
ed1e77d3 A |
334 | if (RefPtr<AtomicStringImpl> existingAtomicString = asString(property)->toExistingAtomicString(exec)) { |
335 | if (JSValue result = base->fastGetOwnProperty(vm, structure, existingAtomicString.get())) | |
336 | return JSValue::encode(result); | |
337 | } | |
81345200 | 338 | } |
6fe7ccc8 | 339 | } |
14957cd0 | 340 | |
ed1e77d3 A |
341 | auto propertyName = property.toPropertyKey(exec); |
342 | if (exec->hadException()) | |
343 | return JSValue::encode(jsUndefined()); | |
344 | return JSValue::encode(JSValue(base).get(exec, propertyName)); | |
6fe7ccc8 | 345 | } |
14957cd0 | 346 | |
81345200 | 347 | ALWAYS_INLINE EncodedJSValue getByValCellInt(ExecState* exec, JSCell* base, int32_t index) |
93a37866 A |
348 | { |
349 | VM* vm = &exec->vm(); | |
350 | NativeCallFrameTracer tracer(vm, exec); | |
351 | ||
352 | if (index < 0) { | |
353 | // Go the slowest way possible becase negative indices don't use indexed storage. | |
354 | return JSValue::encode(JSValue(base).get(exec, Identifier::from(exec, index))); | |
355 | } | |
356 | ||
357 | // Use this since we know that the value is out of bounds. | |
358 | return JSValue::encode(JSValue(base).get(exec, index)); | |
359 | } | |
360 | ||
81345200 | 361 | EncodedJSValue JIT_OPERATION operationGetByValArrayInt(ExecState* exec, JSArray* base, int32_t index) |
14957cd0 | 362 | { |
81345200 | 363 | return getByValCellInt(exec, base, index); |
6fe7ccc8 | 364 | } |
14957cd0 | 365 | |
81345200 | 366 | EncodedJSValue JIT_OPERATION operationGetByValStringInt(ExecState* exec, JSString* base, int32_t index) |
6fe7ccc8 | 367 | { |
81345200 | 368 | return getByValCellInt(exec, base, index); |
6fe7ccc8 | 369 | } |
14957cd0 | 370 | |
81345200 | 371 | void JIT_OPERATION operationPutByValStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) |
6fe7ccc8 | 372 | { |
93a37866 A |
373 | VM* vm = &exec->vm(); |
374 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 | 375 | |
81345200 | 376 | operationPutByValInternal<true, false>(exec, encodedBase, encodedProperty, encodedValue); |
6fe7ccc8 | 377 | } |
14957cd0 | 378 | |
81345200 | 379 | void JIT_OPERATION operationPutByValNonStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) |
6fe7ccc8 | 380 | { |
93a37866 A |
381 | VM* vm = &exec->vm(); |
382 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 | 383 | |
81345200 | 384 | operationPutByValInternal<false, false>(exec, encodedBase, encodedProperty, encodedValue); |
6fe7ccc8 A |
385 | } |
386 | ||
81345200 | 387 | void JIT_OPERATION operationPutByValCellStrict(ExecState* exec, JSCell* cell, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) |
6fe7ccc8 | 388 | { |
93a37866 A |
389 | VM* vm = &exec->vm(); |
390 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 | 391 | |
81345200 | 392 | operationPutByValInternal<true, false>(exec, JSValue::encode(cell), encodedProperty, encodedValue); |
6fe7ccc8 A |
393 | } |
394 | ||
81345200 | 395 | void JIT_OPERATION operationPutByValCellNonStrict(ExecState* exec, JSCell* cell, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) |
6fe7ccc8 | 396 | { |
93a37866 A |
397 | VM* vm = &exec->vm(); |
398 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 | 399 | |
81345200 | 400 | operationPutByValInternal<false, false>(exec, JSValue::encode(cell), encodedProperty, encodedValue); |
6fe7ccc8 A |
401 | } |
402 | ||
81345200 | 403 | void JIT_OPERATION operationPutByValBeyondArrayBoundsStrict(ExecState* exec, JSObject* array, int32_t index, EncodedJSValue encodedValue) |
6fe7ccc8 | 404 | { |
81345200 A |
405 | VM& vm = exec->vm(); |
406 | NativeCallFrameTracer tracer(&vm, exec); | |
6fe7ccc8 A |
407 | |
408 | if (index >= 0) { | |
93a37866 | 409 | array->putByIndexInline(exec, index, JSValue::decode(encodedValue), true); |
6fe7ccc8 A |
410 | return; |
411 | } | |
412 | ||
81345200 | 413 | PutPropertySlot slot(array, true); |
6fe7ccc8 A |
414 | array->methodTable()->put( |
415 | array, exec, Identifier::from(exec, index), JSValue::decode(encodedValue), slot); | |
416 | } | |
14957cd0 | 417 | |
81345200 | 418 | void JIT_OPERATION operationPutByValBeyondArrayBoundsNonStrict(ExecState* exec, JSObject* array, int32_t index, EncodedJSValue encodedValue) |
6fe7ccc8 | 419 | { |
93a37866 A |
420 | VM* vm = &exec->vm(); |
421 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 A |
422 | |
423 | if (index >= 0) { | |
93a37866 | 424 | array->putByIndexInline(exec, index, JSValue::decode(encodedValue), false); |
14957cd0 A |
425 | return; |
426 | } | |
6fe7ccc8 | 427 | |
81345200 | 428 | PutPropertySlot slot(array, false); |
6fe7ccc8 A |
429 | array->methodTable()->put( |
430 | array, exec, Identifier::from(exec, index), JSValue::decode(encodedValue), slot); | |
431 | } | |
14957cd0 | 432 | |
81345200 | 433 | void JIT_OPERATION operationPutDoubleByValBeyondArrayBoundsStrict(ExecState* exec, JSObject* array, int32_t index, double value) |
93a37866 A |
434 | { |
435 | VM* vm = &exec->vm(); | |
436 | NativeCallFrameTracer tracer(vm, exec); | |
437 | ||
438 | JSValue jsValue = JSValue(JSValue::EncodeAsDouble, value); | |
439 | ||
440 | if (index >= 0) { | |
441 | array->putByIndexInline(exec, index, jsValue, true); | |
442 | return; | |
443 | } | |
444 | ||
81345200 | 445 | PutPropertySlot slot(array, true); |
93a37866 A |
446 | array->methodTable()->put( |
447 | array, exec, Identifier::from(exec, index), jsValue, slot); | |
448 | } | |
449 | ||
81345200 | 450 | void JIT_OPERATION operationPutDoubleByValBeyondArrayBoundsNonStrict(ExecState* exec, JSObject* array, int32_t index, double value) |
93a37866 A |
451 | { |
452 | VM* vm = &exec->vm(); | |
453 | NativeCallFrameTracer tracer(vm, exec); | |
454 | ||
455 | JSValue jsValue = JSValue(JSValue::EncodeAsDouble, value); | |
456 | ||
457 | if (index >= 0) { | |
458 | array->putByIndexInline(exec, index, jsValue, false); | |
459 | return; | |
460 | } | |
461 | ||
81345200 | 462 | PutPropertySlot slot(array, false); |
93a37866 A |
463 | array->methodTable()->put( |
464 | array, exec, Identifier::from(exec, index), jsValue, slot); | |
465 | } | |
466 | ||
81345200 | 467 | void JIT_OPERATION operationPutByValDirectStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) |
14957cd0 | 468 | { |
93a37866 A |
469 | VM* vm = &exec->vm(); |
470 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 | 471 | |
81345200 | 472 | operationPutByValInternal<true, true>(exec, encodedBase, encodedProperty, encodedValue); |
6fe7ccc8 A |
473 | } |
474 | ||
81345200 | 475 | void JIT_OPERATION operationPutByValDirectNonStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) |
6fe7ccc8 | 476 | { |
93a37866 A |
477 | VM* vm = &exec->vm(); |
478 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 | 479 | |
81345200 | 480 | operationPutByValInternal<false, true>(exec, encodedBase, encodedProperty, encodedValue); |
6fe7ccc8 A |
481 | } |
482 | ||
81345200 | 483 | void JIT_OPERATION operationPutByValDirectCellStrict(ExecState* exec, JSCell* cell, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) |
6fe7ccc8 | 484 | { |
93a37866 A |
485 | VM* vm = &exec->vm(); |
486 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 | 487 | |
81345200 | 488 | operationPutByValInternal<true, true>(exec, JSValue::encode(cell), encodedProperty, encodedValue); |
6fe7ccc8 A |
489 | } |
490 | ||
81345200 | 491 | void JIT_OPERATION operationPutByValDirectCellNonStrict(ExecState* exec, JSCell* cell, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) |
6fe7ccc8 | 492 | { |
93a37866 A |
493 | VM* vm = &exec->vm(); |
494 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 | 495 | |
81345200 | 496 | operationPutByValInternal<false, true>(exec, JSValue::encode(cell), encodedProperty, encodedValue); |
6fe7ccc8 A |
497 | } |
498 | ||
81345200 | 499 | void JIT_OPERATION operationPutByValDirectBeyondArrayBoundsStrict(ExecState* exec, JSObject* array, int32_t index, EncodedJSValue encodedValue) |
6fe7ccc8 | 500 | { |
93a37866 A |
501 | VM* vm = &exec->vm(); |
502 | NativeCallFrameTracer tracer(vm, exec); | |
81345200 A |
503 | if (index >= 0) { |
504 | array->putDirectIndex(exec, index, JSValue::decode(encodedValue), 0, PutDirectIndexShouldThrow); | |
93a37866 | 505 | return; |
81345200 | 506 | } |
6fe7ccc8 | 507 | |
81345200 A |
508 | PutPropertySlot slot(array, true); |
509 | array->putDirect(exec->vm(), Identifier::from(exec, index), JSValue::decode(encodedValue), slot); | |
6fe7ccc8 A |
510 | } |
511 | ||
81345200 | 512 | void JIT_OPERATION operationPutByValDirectBeyondArrayBoundsNonStrict(ExecState* exec, JSObject* array, int32_t index, EncodedJSValue encodedValue) |
6fe7ccc8 | 513 | { |
93a37866 A |
514 | VM* vm = &exec->vm(); |
515 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 | 516 | |
81345200 A |
517 | if (index >= 0) { |
518 | array->putDirectIndex(exec, index, JSValue::decode(encodedValue)); | |
93a37866 | 519 | return; |
81345200 | 520 | } |
6fe7ccc8 | 521 | |
81345200 A |
522 | PutPropertySlot slot(array, false); |
523 | array->putDirect(exec->vm(), Identifier::from(exec, index), JSValue::decode(encodedValue), slot); | |
14957cd0 A |
524 | } |
525 | ||
81345200 | 526 | EncodedJSValue JIT_OPERATION operationArrayPush(ExecState* exec, EncodedJSValue encodedValue, JSArray* array) |
14957cd0 | 527 | { |
93a37866 A |
528 | VM* vm = &exec->vm(); |
529 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 | 530 | |
81345200 A |
531 | array->push(exec, JSValue::decode(encodedValue)); |
532 | return JSValue::encode(jsNumber(array->length())); | |
14957cd0 A |
533 | } |
534 | ||
81345200 | 535 | EncodedJSValue JIT_OPERATION operationArrayPushDouble(ExecState* exec, double value, JSArray* array) |
14957cd0 | 536 | { |
93a37866 A |
537 | VM* vm = &exec->vm(); |
538 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 | 539 | |
81345200 A |
540 | array->push(exec, JSValue(JSValue::EncodeAsDouble, value)); |
541 | return JSValue::encode(jsNumber(array->length())); | |
14957cd0 A |
542 | } |
543 | ||
81345200 | 544 | EncodedJSValue JIT_OPERATION operationArrayPop(ExecState* exec, JSArray* array) |
14957cd0 | 545 | { |
93a37866 A |
546 | VM* vm = &exec->vm(); |
547 | NativeCallFrameTracer tracer(vm, exec); | |
548 | ||
81345200 | 549 | return JSValue::encode(array->pop(exec)); |
14957cd0 | 550 | } |
81345200 A |
551 | |
552 | EncodedJSValue JIT_OPERATION operationArrayPopAndRecoverLength(ExecState* exec, JSArray* array) | |
14957cd0 | 553 | { |
93a37866 A |
554 | VM* vm = &exec->vm(); |
555 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 | 556 | |
81345200 | 557 | array->butterfly()->setPublicLength(array->butterfly()->publicLength() + 1); |
6fe7ccc8 | 558 | |
81345200 | 559 | return JSValue::encode(array->pop(exec)); |
14957cd0 | 560 | } |
81345200 A |
561 | |
562 | EncodedJSValue JIT_OPERATION operationRegExpExec(ExecState* exec, JSCell* base, JSCell* argument) | |
14957cd0 | 563 | { |
81345200 A |
564 | VM& vm = exec->vm(); |
565 | NativeCallFrameTracer tracer(&vm, exec); | |
6fe7ccc8 | 566 | |
81345200 A |
567 | if (!base->inherits(RegExpObject::info())) |
568 | return throwVMTypeError(exec); | |
14957cd0 | 569 | |
81345200 A |
570 | ASSERT(argument->isString() || argument->isObject()); |
571 | JSString* input = argument->isString() ? asString(argument) : asObject(argument)->toString(exec); | |
572 | return JSValue::encode(asRegExpObject(base)->exec(exec, input)); | |
14957cd0 | 573 | } |
81345200 A |
574 | |
575 | size_t JIT_OPERATION operationRegExpTest(ExecState* exec, JSCell* base, JSCell* argument) | |
14957cd0 | 576 | { |
81345200 A |
577 | VM& vm = exec->vm(); |
578 | NativeCallFrameTracer tracer(&vm, exec); | |
14957cd0 | 579 | |
81345200 A |
580 | if (!base->inherits(RegExpObject::info())) { |
581 | throwTypeError(exec); | |
582 | return false; | |
583 | } | |
6fe7ccc8 | 584 | |
81345200 A |
585 | ASSERT(argument->isString() || argument->isObject()); |
586 | JSString* input = argument->isString() ? asString(argument) : asObject(argument)->toString(exec); | |
587 | return asRegExpObject(base)->test(exec, input); | |
93a37866 A |
588 | } |
589 | ||
81345200 | 590 | size_t JIT_OPERATION operationCompareStrictEqCell(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) |
6fe7ccc8 | 591 | { |
93a37866 A |
592 | VM* vm = &exec->vm(); |
593 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 A |
594 | |
595 | JSValue op1 = JSValue::decode(encodedOp1); | |
596 | JSValue op2 = JSValue::decode(encodedOp2); | |
597 | ||
598 | ASSERT(op1.isCell()); | |
599 | ASSERT(op2.isCell()); | |
600 | ||
601 | return JSValue::strictEqualSlowCaseInline(exec, op1, op2); | |
602 | } | |
603 | ||
81345200 | 604 | size_t JIT_OPERATION operationCompareStrictEq(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) |
6fe7ccc8 | 605 | { |
93a37866 A |
606 | VM* vm = &exec->vm(); |
607 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 A |
608 | |
609 | JSValue src1 = JSValue::decode(encodedOp1); | |
610 | JSValue src2 = JSValue::decode(encodedOp2); | |
611 | ||
612 | return JSValue::strictEqual(exec, src1, src2); | |
613 | } | |
614 | ||
81345200 | 615 | EncodedJSValue JIT_OPERATION operationToPrimitive(ExecState* exec, EncodedJSValue value) |
6fe7ccc8 | 616 | { |
93a37866 | 617 | VM* vm = &exec->vm(); |
81345200 | 618 | NativeCallFrameTracer tracer(vm, exec); |
6fe7ccc8 | 619 | |
81345200 | 620 | return JSValue::encode(JSValue::decode(value).toPrimitive(exec)); |
6fe7ccc8 A |
621 | } |
622 | ||
81345200 | 623 | char* JIT_OPERATION operationNewArray(ExecState* exec, Structure* arrayStructure, void* buffer, size_t size) |
6fe7ccc8 | 624 | { |
93a37866 A |
625 | VM* vm = &exec->vm(); |
626 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 | 627 | |
81345200 | 628 | return bitwise_cast<char*>(constructArray(exec, arrayStructure, static_cast<JSValue*>(buffer), size)); |
6fe7ccc8 A |
629 | } |
630 | ||
81345200 | 631 | char* JIT_OPERATION operationNewEmptyArray(ExecState* exec, Structure* arrayStructure) |
6fe7ccc8 | 632 | { |
81345200 A |
633 | VM* vm = &exec->vm(); |
634 | NativeCallFrameTracer tracer(vm, exec); | |
635 | ||
636 | return bitwise_cast<char*>(JSArray::create(*vm, arrayStructure)); | |
6fe7ccc8 A |
637 | } |
638 | ||
81345200 | 639 | char* JIT_OPERATION operationNewArrayWithSize(ExecState* exec, Structure* arrayStructure, int32_t size) |
6fe7ccc8 | 640 | { |
93a37866 A |
641 | VM* vm = &exec->vm(); |
642 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 | 643 | |
81345200 A |
644 | if (UNLIKELY(size < 0)) |
645 | return bitwise_cast<char*>(exec->vm().throwException(exec, createRangeError(exec, ASCIILiteral("Array size is not a small enough positive integer.")))); | |
646 | ||
647 | return bitwise_cast<char*>(JSArray::create(*vm, arrayStructure, size)); | |
6fe7ccc8 A |
648 | } |
649 | ||
81345200 | 650 | char* JIT_OPERATION operationNewArrayBuffer(ExecState* exec, Structure* arrayStructure, size_t start, size_t size) |
93a37866 | 651 | { |
81345200 A |
652 | VM& vm = exec->vm(); |
653 | NativeCallFrameTracer tracer(&vm, exec); | |
654 | return bitwise_cast<char*>(constructArray(exec, arrayStructure, exec->codeBlock()->constantBuffer(start), size)); | |
6fe7ccc8 A |
655 | } |
656 | ||
81345200 A |
657 | char* JIT_OPERATION operationNewInt8ArrayWithSize( |
658 | ExecState* exec, Structure* structure, int32_t length) | |
6fe7ccc8 | 659 | { |
81345200 | 660 | return newTypedArrayWithSize<JSInt8Array>(exec, structure, length); |
6fe7ccc8 A |
661 | } |
662 | ||
81345200 A |
663 | char* JIT_OPERATION operationNewInt8ArrayWithOneArgument( |
664 | ExecState* exec, Structure* structure, EncodedJSValue encodedValue) | |
6fe7ccc8 | 665 | { |
81345200 | 666 | return newTypedArrayWithOneArgument<JSInt8Array>(exec, structure, encodedValue); |
93a37866 | 667 | } |
6fe7ccc8 | 668 | |
81345200 A |
669 | char* JIT_OPERATION operationNewInt16ArrayWithSize( |
670 | ExecState* exec, Structure* structure, int32_t length) | |
671 | { | |
672 | return newTypedArrayWithSize<JSInt16Array>(exec, structure, length); | |
93a37866 | 673 | } |
6fe7ccc8 | 674 | |
81345200 A |
675 | char* JIT_OPERATION operationNewInt16ArrayWithOneArgument( |
676 | ExecState* exec, Structure* structure, EncodedJSValue encodedValue) | |
93a37866 | 677 | { |
81345200 | 678 | return newTypedArrayWithOneArgument<JSInt16Array>(exec, structure, encodedValue); |
6fe7ccc8 A |
679 | } |
680 | ||
81345200 A |
681 | char* JIT_OPERATION operationNewInt32ArrayWithSize( |
682 | ExecState* exec, Structure* structure, int32_t length) | |
6fe7ccc8 | 683 | { |
81345200 | 684 | return newTypedArrayWithSize<JSInt32Array>(exec, structure, length); |
6fe7ccc8 A |
685 | } |
686 | ||
81345200 A |
687 | char* JIT_OPERATION operationNewInt32ArrayWithOneArgument( |
688 | ExecState* exec, Structure* structure, EncodedJSValue encodedValue) | |
6fe7ccc8 | 689 | { |
81345200 | 690 | return newTypedArrayWithOneArgument<JSInt32Array>(exec, structure, encodedValue); |
6fe7ccc8 A |
691 | } |
692 | ||
81345200 A |
693 | char* JIT_OPERATION operationNewUint8ArrayWithSize( |
694 | ExecState* exec, Structure* structure, int32_t length) | |
6fe7ccc8 | 695 | { |
81345200 | 696 | return newTypedArrayWithSize<JSUint8Array>(exec, structure, length); |
93a37866 | 697 | } |
6fe7ccc8 | 698 | |
81345200 A |
699 | char* JIT_OPERATION operationNewUint8ArrayWithOneArgument( |
700 | ExecState* exec, Structure* structure, EncodedJSValue encodedValue) | |
93a37866 | 701 | { |
81345200 | 702 | return newTypedArrayWithOneArgument<JSUint8Array>(exec, structure, encodedValue); |
93a37866 | 703 | } |
6fe7ccc8 | 704 | |
81345200 A |
705 | char* JIT_OPERATION operationNewUint8ClampedArrayWithSize( |
706 | ExecState* exec, Structure* structure, int32_t length) | |
93a37866 | 707 | { |
81345200 | 708 | return newTypedArrayWithSize<JSUint8ClampedArray>(exec, structure, length); |
6fe7ccc8 A |
709 | } |
710 | ||
81345200 A |
711 | char* JIT_OPERATION operationNewUint8ClampedArrayWithOneArgument( |
712 | ExecState* exec, Structure* structure, EncodedJSValue encodedValue) | |
6fe7ccc8 | 713 | { |
81345200 | 714 | return newTypedArrayWithOneArgument<JSUint8ClampedArray>(exec, structure, encodedValue); |
6fe7ccc8 A |
715 | } |
716 | ||
81345200 A |
717 | char* JIT_OPERATION operationNewUint16ArrayWithSize( |
718 | ExecState* exec, Structure* structure, int32_t length) | |
6fe7ccc8 | 719 | { |
81345200 | 720 | return newTypedArrayWithSize<JSUint16Array>(exec, structure, length); |
93a37866 | 721 | } |
6fe7ccc8 | 722 | |
81345200 A |
723 | char* JIT_OPERATION operationNewUint16ArrayWithOneArgument( |
724 | ExecState* exec, Structure* structure, EncodedJSValue encodedValue) | |
93a37866 | 725 | { |
81345200 | 726 | return newTypedArrayWithOneArgument<JSUint16Array>(exec, structure, encodedValue); |
6fe7ccc8 A |
727 | } |
728 | ||
81345200 A |
729 | char* JIT_OPERATION operationNewUint32ArrayWithSize( |
730 | ExecState* exec, Structure* structure, int32_t length) | |
6fe7ccc8 | 731 | { |
81345200 A |
732 | return newTypedArrayWithSize<JSUint32Array>(exec, structure, length); |
733 | } | |
93a37866 | 734 | |
81345200 A |
735 | char* JIT_OPERATION operationNewUint32ArrayWithOneArgument( |
736 | ExecState* exec, Structure* structure, EncodedJSValue encodedValue) | |
737 | { | |
738 | return newTypedArrayWithOneArgument<JSUint32Array>(exec, structure, encodedValue); | |
6fe7ccc8 A |
739 | } |
740 | ||
81345200 A |
741 | char* JIT_OPERATION operationNewFloat32ArrayWithSize( |
742 | ExecState* exec, Structure* structure, int32_t length) | |
6fe7ccc8 | 743 | { |
81345200 | 744 | return newTypedArrayWithSize<JSFloat32Array>(exec, structure, length); |
6fe7ccc8 A |
745 | } |
746 | ||
81345200 A |
747 | char* JIT_OPERATION operationNewFloat32ArrayWithOneArgument( |
748 | ExecState* exec, Structure* structure, EncodedJSValue encodedValue) | |
6fe7ccc8 | 749 | { |
81345200 | 750 | return newTypedArrayWithOneArgument<JSFloat32Array>(exec, structure, encodedValue); |
6fe7ccc8 A |
751 | } |
752 | ||
81345200 A |
753 | char* JIT_OPERATION operationNewFloat64ArrayWithSize( |
754 | ExecState* exec, Structure* structure, int32_t length) | |
6fe7ccc8 | 755 | { |
81345200 | 756 | return newTypedArrayWithSize<JSFloat64Array>(exec, structure, length); |
6fe7ccc8 A |
757 | } |
758 | ||
81345200 A |
759 | char* JIT_OPERATION operationNewFloat64ArrayWithOneArgument( |
760 | ExecState* exec, Structure* structure, EncodedJSValue encodedValue) | |
93a37866 | 761 | { |
81345200 | 762 | return newTypedArrayWithOneArgument<JSFloat64Array>(exec, structure, encodedValue); |
93a37866 A |
763 | } |
764 | ||
ed1e77d3 | 765 | JSCell* JIT_OPERATION operationCreateActivationDirect(ExecState* exec, Structure* structure, JSScope* scope, SymbolTable* table) |
93a37866 A |
766 | { |
767 | VM& vm = exec->vm(); | |
768 | NativeCallFrameTracer tracer(&vm, exec); | |
ed1e77d3 A |
769 | return JSLexicalEnvironment::create(vm, structure, scope, table); |
770 | } | |
771 | ||
772 | JSCell* JIT_OPERATION operationCreateDirectArguments(ExecState* exec, Structure* structure, int32_t length, int32_t minCapacity) | |
773 | { | |
774 | VM& vm = exec->vm(); | |
775 | NativeCallFrameTracer target(&vm, exec); | |
776 | DirectArguments* result = DirectArguments::create( | |
777 | vm, structure, length, std::max(length, minCapacity)); | |
778 | // The caller will store to this object without barriers. Most likely, at this point, this is | |
779 | // still a young object and so no barriers are needed. But it's good to be careful anyway, | |
780 | // since the GC should be allowed to do crazy (like pretenuring, for example). | |
781 | vm.heap.writeBarrier(result); | |
93a37866 A |
782 | return result; |
783 | } | |
784 | ||
ed1e77d3 | 785 | JSCell* JIT_OPERATION operationCreateScopedArguments(ExecState* exec, Structure* structure, Register* argumentStart, int32_t length, JSFunction* callee, JSLexicalEnvironment* scope) |
93a37866 | 786 | { |
ed1e77d3 A |
787 | VM& vm = exec->vm(); |
788 | NativeCallFrameTracer target(&vm, exec); | |
789 | ||
790 | // We could pass the ScopedArgumentsTable* as an argument. We currently don't because I | |
791 | // didn't feel like changing the max number of arguments for a slow path call from 6 to 7. | |
792 | ScopedArgumentsTable* table = scope->symbolTable()->arguments(); | |
793 | ||
794 | return ScopedArguments::createByCopyingFrom( | |
795 | vm, structure, argumentStart, length, callee, table, scope); | |
93a37866 A |
796 | } |
797 | ||
ed1e77d3 | 798 | JSCell* JIT_OPERATION operationCreateClonedArguments(ExecState* exec, Structure* structure, Register* argumentStart, int32_t length, JSFunction* callee) |
93a37866 | 799 | { |
ed1e77d3 A |
800 | VM& vm = exec->vm(); |
801 | NativeCallFrameTracer target(&vm, exec); | |
802 | return ClonedArguments::createByCopyingFrom( | |
803 | exec, structure, argumentStart, length, callee); | |
93a37866 A |
804 | } |
805 | ||
ed1e77d3 | 806 | JSCell* JIT_OPERATION operationCreateDirectArgumentsDuringExit(ExecState* exec, InlineCallFrame* inlineCallFrame, JSFunction* callee, int32_t argumentCount) |
6fe7ccc8 | 807 | { |
93a37866 | 808 | VM& vm = exec->vm(); |
ed1e77d3 A |
809 | NativeCallFrameTracer target(&vm, exec); |
810 | ||
811 | DeferGCForAWhile deferGC(vm.heap); | |
812 | ||
813 | CodeBlock* codeBlock; | |
814 | if (inlineCallFrame) | |
815 | codeBlock = baselineCodeBlockForInlineCallFrame(inlineCallFrame); | |
816 | else | |
817 | codeBlock = exec->codeBlock(); | |
818 | ||
819 | unsigned length = argumentCount - 1; | |
820 | unsigned capacity = std::max(length, static_cast<unsigned>(codeBlock->numParameters() - 1)); | |
821 | DirectArguments* result = DirectArguments::create( | |
822 | vm, codeBlock->globalObject()->directArgumentsStructure(), length, capacity); | |
823 | ||
824 | result->callee().set(vm, result, callee); | |
825 | ||
826 | Register* arguments = | |
827 | exec->registers() + (inlineCallFrame ? inlineCallFrame->stackOffset : 0) + | |
828 | CallFrame::argumentOffset(0); | |
829 | for (unsigned i = length; i--;) | |
830 | result->setIndexQuickly(vm, i, arguments[i].jsValue()); | |
831 | ||
832 | return result; | |
833 | } | |
93a37866 | 834 | |
ed1e77d3 A |
835 | JSCell* JIT_OPERATION operationCreateClonedArgumentsDuringExit(ExecState* exec, InlineCallFrame* inlineCallFrame, JSFunction* callee, int32_t argumentCount) |
836 | { | |
837 | VM& vm = exec->vm(); | |
838 | NativeCallFrameTracer target(&vm, exec); | |
839 | ||
840 | DeferGCForAWhile deferGC(vm.heap); | |
93a37866 | 841 | |
ed1e77d3 A |
842 | CodeBlock* codeBlock; |
843 | if (inlineCallFrame) | |
844 | codeBlock = baselineCodeBlockForInlineCallFrame(inlineCallFrame); | |
845 | else | |
846 | codeBlock = exec->codeBlock(); | |
93a37866 | 847 | |
ed1e77d3 A |
848 | unsigned length = argumentCount - 1; |
849 | ClonedArguments* result = ClonedArguments::createEmpty( | |
850 | vm, codeBlock->globalObject()->outOfBandArgumentsStructure(), callee); | |
851 | ||
852 | Register* arguments = | |
853 | exec->registers() + (inlineCallFrame ? inlineCallFrame->stackOffset : 0) + | |
854 | CallFrame::argumentOffset(0); | |
855 | for (unsigned i = length; i--;) | |
856 | result->putDirectIndex(exec, i, arguments[i].jsValue()); | |
857 | ||
858 | result->putDirect(vm, vm.propertyNames->length, jsNumber(length)); | |
859 | ||
860 | return result; | |
93a37866 A |
861 | } |
862 | ||
ed1e77d3 | 863 | size_t JIT_OPERATION operationObjectIsObject(ExecState* exec, JSGlobalObject* globalObject, JSCell* object) |
93a37866 A |
864 | { |
865 | VM& vm = exec->vm(); | |
866 | NativeCallFrameTracer tracer(&vm, exec); | |
867 | ||
ed1e77d3 | 868 | ASSERT(jsDynamicCast<JSObject*>(object)); |
93a37866 | 869 | |
ed1e77d3 A |
870 | if (object->structure(vm)->masqueradesAsUndefined(globalObject)) |
871 | return false; | |
872 | if (object->type() == JSFunctionType) | |
873 | return false; | |
874 | if (object->inlineTypeFlags() & TypeOfShouldCallGetCallData) { | |
875 | CallData callData; | |
876 | if (object->methodTable(vm)->getCallData(object, callData) != CallTypeNone) | |
877 | return false; | |
93a37866 A |
878 | } |
879 | ||
ed1e77d3 | 880 | return true; |
93a37866 A |
881 | } |
882 | ||
ed1e77d3 | 883 | size_t JIT_OPERATION operationObjectIsFunction(ExecState* exec, JSGlobalObject* globalObject, JSCell* object) |
6fe7ccc8 | 884 | { |
93a37866 A |
885 | VM& vm = exec->vm(); |
886 | NativeCallFrameTracer tracer(&vm, exec); | |
6fe7ccc8 | 887 | |
ed1e77d3 A |
888 | ASSERT(jsDynamicCast<JSObject*>(object)); |
889 | ||
890 | if (object->structure(vm)->masqueradesAsUndefined(globalObject)) | |
891 | return false; | |
892 | if (object->type() == JSFunctionType) | |
893 | return true; | |
894 | if (object->inlineTypeFlags() & TypeOfShouldCallGetCallData) { | |
895 | CallData callData; | |
896 | if (object->methodTable(vm)->getCallData(object, callData) != CallTypeNone) | |
897 | return true; | |
898 | } | |
899 | ||
900 | return false; | |
6fe7ccc8 A |
901 | } |
902 | ||
ed1e77d3 | 903 | JSCell* JIT_OPERATION operationTypeOfObject(ExecState* exec, JSGlobalObject* globalObject, JSCell* object) |
6fe7ccc8 | 904 | { |
ed1e77d3 A |
905 | VM& vm = exec->vm(); |
906 | NativeCallFrameTracer tracer(&vm, exec); | |
907 | ||
908 | ASSERT(jsDynamicCast<JSObject*>(object)); | |
909 | ||
910 | if (object->structure(vm)->masqueradesAsUndefined(globalObject)) | |
911 | return vm.smallStrings.undefinedString(); | |
912 | if (object->type() == JSFunctionType) | |
913 | return vm.smallStrings.functionString(); | |
914 | if (object->inlineTypeFlags() & TypeOfShouldCallGetCallData) { | |
915 | CallData callData; | |
916 | if (object->methodTable(vm)->getCallData(object, callData) != CallTypeNone) | |
917 | return vm.smallStrings.functionString(); | |
918 | } | |
919 | ||
920 | return vm.smallStrings.objectString(); | |
6fe7ccc8 A |
921 | } |
922 | ||
ed1e77d3 | 923 | int32_t JIT_OPERATION operationTypeOfObjectAsTypeofType(ExecState* exec, JSGlobalObject* globalObject, JSCell* object) |
93a37866 A |
924 | { |
925 | VM& vm = exec->vm(); | |
926 | NativeCallFrameTracer tracer(&vm, exec); | |
ed1e77d3 A |
927 | |
928 | ASSERT(jsDynamicCast<JSObject*>(object)); | |
929 | ||
930 | if (object->structure(vm)->masqueradesAsUndefined(globalObject)) | |
931 | return static_cast<int32_t>(TypeofType::Undefined); | |
932 | if (object->type() == JSFunctionType) | |
933 | return static_cast<int32_t>(TypeofType::Function); | |
934 | if (object->inlineTypeFlags() & TypeOfShouldCallGetCallData) { | |
935 | CallData callData; | |
936 | if (object->methodTable(vm)->getCallData(object, callData) != CallTypeNone) | |
937 | return static_cast<int32_t>(TypeofType::Function); | |
938 | } | |
939 | ||
940 | return static_cast<int32_t>(TypeofType::Object); | |
93a37866 A |
941 | } |
942 | ||
81345200 | 943 | char* JIT_OPERATION operationAllocatePropertyStorageWithInitialCapacity(ExecState* exec) |
93a37866 A |
944 | { |
945 | VM& vm = exec->vm(); | |
946 | NativeCallFrameTracer tracer(&vm, exec); | |
947 | ||
948 | return reinterpret_cast<char*>( | |
81345200 | 949 | Butterfly::createUninitialized(vm, 0, 0, initialOutOfLineCapacity, false, 0)); |
93a37866 A |
950 | } |
951 | ||
81345200 | 952 | char* JIT_OPERATION operationAllocatePropertyStorage(ExecState* exec, size_t newSize) |
93a37866 A |
953 | { |
954 | VM& vm = exec->vm(); | |
955 | NativeCallFrameTracer tracer(&vm, exec); | |
956 | ||
957 | return reinterpret_cast<char*>( | |
81345200 | 958 | Butterfly::createUninitialized(vm, 0, 0, newSize, false, 0)); |
93a37866 A |
959 | } |
960 | ||
81345200 | 961 | char* JIT_OPERATION operationReallocateButterflyToHavePropertyStorageWithInitialCapacity(ExecState* exec, JSObject* object) |
93a37866 A |
962 | { |
963 | VM& vm = exec->vm(); | |
964 | NativeCallFrameTracer tracer(&vm, exec); | |
965 | ||
966 | ASSERT(!object->structure()->outOfLineCapacity()); | |
81345200 | 967 | DeferGC deferGC(vm.heap); |
93a37866 | 968 | Butterfly* result = object->growOutOfLineStorage(vm, 0, initialOutOfLineCapacity); |
81345200 | 969 | object->setButterflyWithoutChangingStructure(vm, result); |
93a37866 A |
970 | return reinterpret_cast<char*>(result); |
971 | } | |
972 | ||
81345200 | 973 | char* JIT_OPERATION operationReallocateButterflyToGrowPropertyStorage(ExecState* exec, JSObject* object, size_t newSize) |
93a37866 A |
974 | { |
975 | VM& vm = exec->vm(); | |
976 | NativeCallFrameTracer tracer(&vm, exec); | |
977 | ||
81345200 | 978 | DeferGC deferGC(vm.heap); |
93a37866 | 979 | Butterfly* result = object->growOutOfLineStorage(vm, object->structure()->outOfLineCapacity(), newSize); |
81345200 | 980 | object->setButterflyWithoutChangingStructure(vm, result); |
93a37866 A |
981 | return reinterpret_cast<char*>(result); |
982 | } | |
983 | ||
81345200 | 984 | char* JIT_OPERATION operationEnsureInt32(ExecState* exec, JSCell* cell) |
93a37866 A |
985 | { |
986 | VM& vm = exec->vm(); | |
987 | NativeCallFrameTracer tracer(&vm, exec); | |
988 | ||
989 | if (!cell->isObject()) | |
990 | return 0; | |
991 | ||
992 | return reinterpret_cast<char*>(asObject(cell)->ensureInt32(vm).data()); | |
993 | } | |
994 | ||
81345200 | 995 | char* JIT_OPERATION operationEnsureDouble(ExecState* exec, JSCell* cell) |
93a37866 A |
996 | { |
997 | VM& vm = exec->vm(); | |
998 | NativeCallFrameTracer tracer(&vm, exec); | |
999 | ||
1000 | if (!cell->isObject()) | |
1001 | return 0; | |
1002 | ||
1003 | return reinterpret_cast<char*>(asObject(cell)->ensureDouble(vm).data()); | |
1004 | } | |
1005 | ||
81345200 | 1006 | char* JIT_OPERATION operationEnsureContiguous(ExecState* exec, JSCell* cell) |
93a37866 A |
1007 | { |
1008 | VM& vm = exec->vm(); | |
1009 | NativeCallFrameTracer tracer(&vm, exec); | |
1010 | ||
1011 | if (!cell->isObject()) | |
1012 | return 0; | |
1013 | ||
1014 | return reinterpret_cast<char*>(asObject(cell)->ensureContiguous(vm).data()); | |
1015 | } | |
1016 | ||
81345200 | 1017 | char* JIT_OPERATION operationEnsureArrayStorage(ExecState* exec, JSCell* cell) |
93a37866 A |
1018 | { |
1019 | VM& vm = exec->vm(); | |
1020 | NativeCallFrameTracer tracer(&vm, exec); | |
1021 | ||
1022 | if (!cell->isObject()) | |
1023 | return 0; | |
1024 | ||
1025 | return reinterpret_cast<char*>(asObject(cell)->ensureArrayStorage(vm)); | |
1026 | } | |
1027 | ||
81345200 | 1028 | StringImpl* JIT_OPERATION operationResolveRope(ExecState* exec, JSString* string) |
93a37866 A |
1029 | { |
1030 | VM& vm = exec->vm(); | |
1031 | NativeCallFrameTracer tracer(&vm, exec); | |
1032 | ||
1033 | return string->value(exec).impl(); | |
1034 | } | |
1035 | ||
81345200 A |
1036 | JSString* JIT_OPERATION operationSingleCharacterString(ExecState* exec, int32_t character) |
1037 | { | |
1038 | VM& vm = exec->vm(); | |
1039 | NativeCallFrameTracer tracer(&vm, exec); | |
1040 | ||
1041 | return jsSingleCharacterString(exec, static_cast<UChar>(character)); | |
1042 | } | |
1043 | ||
1044 | JSCell* JIT_OPERATION operationNewStringObject(ExecState* exec, JSString* string, Structure* structure) | |
93a37866 A |
1045 | { |
1046 | VM& vm = exec->vm(); | |
1047 | NativeCallFrameTracer tracer(&vm, exec); | |
1048 | ||
81345200 | 1049 | return StringObject::create(vm, structure, string); |
93a37866 A |
1050 | } |
1051 | ||
81345200 | 1052 | JSCell* JIT_OPERATION operationToStringOnCell(ExecState* exec, JSCell* cell) |
93a37866 A |
1053 | { |
1054 | VM& vm = exec->vm(); | |
1055 | NativeCallFrameTracer tracer(&vm, exec); | |
1056 | ||
1057 | return JSValue(cell).toString(exec); | |
1058 | } | |
1059 | ||
81345200 | 1060 | JSCell* JIT_OPERATION operationToString(ExecState* exec, EncodedJSValue value) |
93a37866 A |
1061 | { |
1062 | VM& vm = exec->vm(); | |
1063 | NativeCallFrameTracer tracer(&vm, exec); | |
1064 | ||
1065 | return JSValue::decode(value).toString(exec); | |
1066 | } | |
1067 | ||
ed1e77d3 A |
1068 | JSCell* JIT_OPERATION operationCallStringConstructorOnCell(ExecState* exec, JSCell* cell) |
1069 | { | |
1070 | VM& vm = exec->vm(); | |
1071 | NativeCallFrameTracer tracer(&vm, exec); | |
1072 | ||
1073 | return stringConstructor(exec, cell); | |
1074 | } | |
1075 | ||
1076 | JSCell* JIT_OPERATION operationCallStringConstructor(ExecState* exec, EncodedJSValue value) | |
1077 | { | |
1078 | VM& vm = exec->vm(); | |
1079 | NativeCallFrameTracer tracer(&vm, exec); | |
1080 | ||
1081 | return stringConstructor(exec, JSValue::decode(value)); | |
1082 | } | |
1083 | ||
81345200 | 1084 | JSCell* JIT_OPERATION operationMakeRope2(ExecState* exec, JSString* left, JSString* right) |
93a37866 A |
1085 | { |
1086 | VM& vm = exec->vm(); | |
1087 | NativeCallFrameTracer tracer(&vm, exec); | |
1088 | ||
4be4e309 A |
1089 | if (sumOverflows<int32_t>(left->length(), right->length())) { |
1090 | throwOutOfMemoryError(exec); | |
1091 | return nullptr; | |
1092 | } | |
1093 | ||
93a37866 A |
1094 | return JSRopeString::create(vm, left, right); |
1095 | } | |
1096 | ||
81345200 | 1097 | JSCell* JIT_OPERATION operationMakeRope3(ExecState* exec, JSString* a, JSString* b, JSString* c) |
93a37866 A |
1098 | { |
1099 | VM& vm = exec->vm(); | |
1100 | NativeCallFrameTracer tracer(&vm, exec); | |
1101 | ||
4be4e309 A |
1102 | if (sumOverflows<int32_t>(a->length(), b->length(), c->length())) { |
1103 | throwOutOfMemoryError(exec); | |
1104 | return nullptr; | |
1105 | } | |
1106 | ||
93a37866 A |
1107 | return JSRopeString::create(vm, a, b, c); |
1108 | } | |
1109 | ||
81345200 A |
1110 | char* JIT_OPERATION operationFindSwitchImmTargetForDouble( |
1111 | ExecState* exec, EncodedJSValue encodedValue, size_t tableIndex) | |
6fe7ccc8 | 1112 | { |
81345200 A |
1113 | CodeBlock* codeBlock = exec->codeBlock(); |
1114 | SimpleJumpTable& table = codeBlock->switchJumpTable(tableIndex); | |
1115 | JSValue value = JSValue::decode(encodedValue); | |
1116 | ASSERT(value.isDouble()); | |
1117 | double asDouble = value.asDouble(); | |
1118 | int32_t asInt32 = static_cast<int32_t>(asDouble); | |
1119 | if (asDouble == asInt32) | |
1120 | return static_cast<char*>(table.ctiForValue(asInt32).executableAddress()); | |
1121 | return static_cast<char*>(table.ctiDefault.executableAddress()); | |
6fe7ccc8 A |
1122 | } |
1123 | ||
81345200 | 1124 | char* JIT_OPERATION operationSwitchString(ExecState* exec, size_t tableIndex, JSString* string) |
93a37866 | 1125 | { |
81345200 A |
1126 | VM& vm = exec->vm(); |
1127 | NativeCallFrameTracer tracer(&vm, exec); | |
1128 | ||
1129 | return static_cast<char*>(exec->codeBlock()->stringSwitchJumpTable(tableIndex).ctiForValue(string->value(exec).impl()).executableAddress()); | |
93a37866 A |
1130 | } |
1131 | ||
ed1e77d3 | 1132 | int32_t JIT_OPERATION operationSwitchStringAndGetBranchOffset(ExecState* exec, size_t tableIndex, JSString* string) |
6fe7ccc8 | 1133 | { |
81345200 A |
1134 | VM& vm = exec->vm(); |
1135 | NativeCallFrameTracer tracer(&vm, exec); | |
6fe7ccc8 | 1136 | |
ed1e77d3 A |
1137 | return exec->codeBlock()->stringSwitchJumpTable(tableIndex).offsetForValue(string->value(exec).impl(), std::numeric_limits<int32_t>::min()); |
1138 | } | |
1139 | ||
1140 | void JIT_OPERATION operationNotifyWrite(ExecState* exec, WatchpointSet* set) | |
1141 | { | |
1142 | VM& vm = exec->vm(); | |
1143 | NativeCallFrameTracer tracer(&vm, exec); | |
1144 | ||
1145 | set->touch("Executed NotifyWrite"); | |
1146 | } | |
1147 | ||
1148 | void JIT_OPERATION operationThrowStackOverflowForVarargs(ExecState* exec) | |
1149 | { | |
1150 | VM& vm = exec->vm(); | |
1151 | NativeCallFrameTracer tracer(&vm, exec); | |
1152 | throwStackOverflowError(exec); | |
1153 | } | |
1154 | ||
1155 | int32_t JIT_OPERATION operationSizeOfVarargs(ExecState* exec, EncodedJSValue encodedArguments, int32_t firstVarArgOffset) | |
1156 | { | |
1157 | VM& vm = exec->vm(); | |
1158 | NativeCallFrameTracer tracer(&vm, exec); | |
1159 | JSValue arguments = JSValue::decode(encodedArguments); | |
1160 | ||
1161 | return sizeOfVarargs(exec, arguments, firstVarArgOffset); | |
1162 | } | |
1163 | ||
1164 | void JIT_OPERATION operationLoadVarargs(ExecState* exec, int32_t firstElementDest, EncodedJSValue encodedArguments, int32_t offset, int32_t length, int32_t mandatoryMinimum) | |
1165 | { | |
1166 | VM& vm = exec->vm(); | |
1167 | NativeCallFrameTracer tracer(&vm, exec); | |
1168 | JSValue arguments = JSValue::decode(encodedArguments); | |
1169 | ||
1170 | loadVarargs(exec, VirtualRegister(firstElementDest), arguments, offset, length); | |
1171 | ||
1172 | for (int32_t i = length; i < mandatoryMinimum; ++i) | |
1173 | exec->r(firstElementDest + i) = jsUndefined(); | |
6fe7ccc8 | 1174 | } |
14957cd0 | 1175 | |
81345200 A |
1176 | double JIT_OPERATION operationFModOnInts(int32_t a, int32_t b) |
1177 | { | |
1178 | return fmod(a, b); | |
1179 | } | |
1180 | ||
1181 | JSCell* JIT_OPERATION operationStringFromCharCode(ExecState* exec, int32_t op1) | |
6fe7ccc8 | 1182 | { |
93a37866 A |
1183 | VM* vm = &exec->vm(); |
1184 | NativeCallFrameTracer tracer(vm, exec); | |
81345200 A |
1185 | return JSC::stringFromCharCode(exec, op1); |
1186 | } | |
14957cd0 | 1187 | |
81345200 A |
1188 | int64_t JIT_OPERATION operationConvertBoxedDoubleToInt52(EncodedJSValue encodedValue) |
1189 | { | |
1190 | JSValue value = JSValue::decode(encodedValue); | |
1191 | if (!value.isDouble()) | |
1192 | return JSValue::notInt52; | |
1193 | return tryConvertToInt52(value.asDouble()); | |
14957cd0 A |
1194 | } |
1195 | ||
81345200 | 1196 | int64_t JIT_OPERATION operationConvertDoubleToInt52(double value) |
14957cd0 | 1197 | { |
81345200 | 1198 | return tryConvertToInt52(value); |
14957cd0 A |
1199 | } |
1200 | ||
ed1e77d3 A |
1201 | void JIT_OPERATION operationProcessTypeProfilerLogDFG(ExecState* exec) |
1202 | { | |
1203 | exec->vm().typeProfilerLog()->processLogEntries(ASCIILiteral("Log Full, called from inside DFG.")); | |
1204 | } | |
1205 | ||
81345200 | 1206 | size_t JIT_OPERATION dfgConvertJSValueToInt32(ExecState* exec, EncodedJSValue value) |
14957cd0 | 1207 | { |
93a37866 A |
1208 | VM* vm = &exec->vm(); |
1209 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 | 1210 | |
81345200 A |
1211 | // toInt32/toUInt32 return the same value; we want the value zero extended to fill the register. |
1212 | return JSValue::decode(value).toUInt32(exec); | |
14957cd0 A |
1213 | } |
1214 | ||
81345200 | 1215 | void JIT_OPERATION debugOperationPrintSpeculationFailure(ExecState* exec, void* debugInfoRaw, void* scratch) |
6fe7ccc8 | 1216 | { |
93a37866 A |
1217 | VM* vm = &exec->vm(); |
1218 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 A |
1219 | |
1220 | SpeculationFailureDebugInfo* debugInfo = static_cast<SpeculationFailureDebugInfo*>(debugInfoRaw); | |
1221 | CodeBlock* codeBlock = debugInfo->codeBlock; | |
1222 | CodeBlock* alternative = codeBlock->alternative(); | |
81345200 A |
1223 | dataLog("Speculation failure in ", *codeBlock); |
1224 | dataLog(" @ exit #", vm->osrExitIndex, " (bc#", debugInfo->bytecodeOffset, ", ", exitKindToString(debugInfo->kind), ") with "); | |
93a37866 A |
1225 | if (alternative) { |
1226 | dataLog( | |
1227 | "executeCounter = ", alternative->jitExecuteCounter(), | |
1228 | ", reoptimizationRetryCounter = ", alternative->reoptimizationRetryCounter(), | |
1229 | ", optimizationDelayCounter = ", alternative->optimizationDelayCounter()); | |
1230 | } else | |
1231 | dataLog("no alternative code block (i.e. we've been jettisoned)"); | |
1232 | dataLog(", osrExitCounter = ", codeBlock->osrExitCounter(), "\n"); | |
1233 | dataLog(" GPRs at time of exit:"); | |
1234 | char* scratchPointer = static_cast<char*>(scratch); | |
1235 | for (unsigned i = 0; i < GPRInfo::numberOfRegisters; ++i) { | |
1236 | GPRReg gpr = GPRInfo::toRegister(i); | |
1237 | dataLog(" ", GPRInfo::debugName(gpr), ":", RawPointer(*reinterpret_cast_ptr<void**>(scratchPointer))); | |
1238 | scratchPointer += sizeof(EncodedJSValue); | |
1239 | } | |
1240 | dataLog("\n"); | |
1241 | dataLog(" FPRs at time of exit:"); | |
1242 | for (unsigned i = 0; i < FPRInfo::numberOfRegisters; ++i) { | |
1243 | FPRReg fpr = FPRInfo::toRegister(i); | |
1244 | dataLog(" ", FPRInfo::debugName(fpr), ":"); | |
1245 | uint64_t bits = *reinterpret_cast_ptr<uint64_t*>(scratchPointer); | |
1246 | double value = *reinterpret_cast_ptr<double*>(scratchPointer); | |
1247 | dataLogF("%llx:%lf", static_cast<long long>(bits), value); | |
1248 | scratchPointer += sizeof(EncodedJSValue); | |
1249 | } | |
1250 | dataLog("\n"); | |
6fe7ccc8 | 1251 | } |
93a37866 | 1252 | |
ed1e77d3 | 1253 | extern "C" void JIT_OPERATION triggerReoptimizationNow(CodeBlock* codeBlock, OSRExitBase* exit) |
93a37866 | 1254 | { |
81345200 A |
1255 | // It's sort of preferable that we don't GC while in here. Anyways, doing so wouldn't |
1256 | // really be profitable. | |
1257 | DeferGCForAWhile deferGC(codeBlock->vm()->heap); | |
1258 | ||
1259 | if (Options::verboseOSR()) | |
1260 | dataLog(*codeBlock, ": Entered reoptimize\n"); | |
93a37866 | 1261 | // We must be called with the baseline code block. |
81345200 | 1262 | ASSERT(JITCode::isBaselineCode(codeBlock->jitType())); |
93a37866 A |
1263 | |
1264 | // If I am my own replacement, then reoptimization has already been triggered. | |
1265 | // This can happen in recursive functions. | |
81345200 A |
1266 | if (codeBlock->replacement() == codeBlock) { |
1267 | if (Options::verboseOSR()) | |
1268 | dataLog(*codeBlock, ": Not reoptimizing because we've already been jettisoned.\n"); | |
93a37866 | 1269 | return; |
81345200 A |
1270 | } |
1271 | ||
93a37866 A |
1272 | // Otherwise, the replacement must be optimized code. Use this as an opportunity |
1273 | // to check our logic. | |
1274 | ASSERT(codeBlock->hasOptimizedReplacement()); | |
81345200 A |
1275 | CodeBlock* optimizedCodeBlock = codeBlock->replacement(); |
1276 | ASSERT(JITCode::isOptimizingJIT(optimizedCodeBlock->jitType())); | |
ed1e77d3 A |
1277 | |
1278 | bool didTryToEnterIntoInlinedLoops = false; | |
1279 | for (InlineCallFrame* inlineCallFrame = exit->m_codeOrigin.inlineCallFrame; inlineCallFrame; inlineCallFrame = inlineCallFrame->caller.inlineCallFrame) { | |
1280 | if (inlineCallFrame->executable->didTryToEnterInLoop()) { | |
1281 | didTryToEnterIntoInlinedLoops = true; | |
1282 | break; | |
1283 | } | |
1284 | } | |
81345200 A |
1285 | |
1286 | // In order to trigger reoptimization, one of two things must have happened: | |
1287 | // 1) We exited more than some number of times. | |
1288 | // 2) We exited and got stuck in a loop, and now we're exiting again. | |
1289 | bool didExitABunch = optimizedCodeBlock->shouldReoptimizeNow(); | |
1290 | bool didGetStuckInLoop = | |
ed1e77d3 | 1291 | (codeBlock->checkIfOptimizationThresholdReached() || didTryToEnterIntoInlinedLoops) |
81345200 A |
1292 | && optimizedCodeBlock->shouldReoptimizeFromLoopNow(); |
1293 | ||
1294 | if (!didExitABunch && !didGetStuckInLoop) { | |
1295 | if (Options::verboseOSR()) | |
1296 | dataLog(*codeBlock, ": Not reoptimizing ", *optimizedCodeBlock, " because it either didn't exit enough or didn't loop enough after exit.\n"); | |
1297 | codeBlock->optimizeAfterLongWarmUp(); | |
1298 | return; | |
1299 | } | |
93a37866 | 1300 | |
81345200 | 1301 | optimizedCodeBlock->jettison(Profiler::JettisonDueToOSRExit, CountReoptimization); |
93a37866 | 1302 | } |
6fe7ccc8 | 1303 | |
81345200 A |
1304 | #if ENABLE(FTL_JIT) |
1305 | static void triggerFTLReplacementCompile(VM* vm, CodeBlock* codeBlock, JITCode* jitCode) | |
1306 | { | |
1307 | if (codeBlock->baselineVersion()->m_didFailFTLCompilation) { | |
1308 | if (Options::verboseOSR()) | |
1309 | dataLog("Deferring FTL-optimization of ", *codeBlock, " indefinitely because there was an FTL failure.\n"); | |
1310 | jitCode->dontOptimizeAnytimeSoon(codeBlock); | |
1311 | return; | |
1312 | } | |
1313 | ||
1314 | if (!jitCode->checkIfOptimizationThresholdReached(codeBlock)) { | |
1315 | if (Options::verboseOSR()) | |
1316 | dataLog("Choosing not to FTL-optimize ", *codeBlock, " yet.\n"); | |
1317 | return; | |
1318 | } | |
1319 | ||
1320 | Worklist::State worklistState; | |
1321 | if (Worklist* worklist = existingGlobalFTLWorklistOrNull()) { | |
1322 | worklistState = worklist->completeAllReadyPlansForVM( | |
1323 | *vm, CompilationKey(codeBlock->baselineVersion(), FTLMode)); | |
1324 | } else | |
1325 | worklistState = Worklist::NotKnown; | |
1326 | ||
1327 | if (worklistState == Worklist::Compiling) { | |
1328 | jitCode->setOptimizationThresholdBasedOnCompilationResult( | |
1329 | codeBlock, CompilationDeferred); | |
1330 | return; | |
1331 | } | |
1332 | ||
1333 | if (codeBlock->hasOptimizedReplacement()) { | |
1334 | // That's great, we've compiled the code - next time we call this function, | |
1335 | // we'll enter that replacement. | |
1336 | jitCode->optimizeSoon(codeBlock); | |
1337 | return; | |
1338 | } | |
1339 | ||
1340 | if (worklistState == Worklist::Compiled) { | |
1341 | // This means that we finished compiling, but failed somehow; in that case the | |
1342 | // thresholds will be set appropriately. | |
1343 | if (Options::verboseOSR()) | |
1344 | dataLog("Code block ", *codeBlock, " was compiled but it doesn't have an optimized replacement.\n"); | |
1345 | return; | |
1346 | } | |
14957cd0 | 1347 | |
81345200 A |
1348 | // We need to compile the code. |
1349 | compile( | |
1350 | *vm, codeBlock->newReplacement().get(), codeBlock, FTLMode, UINT_MAX, | |
1351 | Operands<JSValue>(), ToFTLDeferredCompilationCallback::create(codeBlock)); | |
1352 | } | |
6fe7ccc8 | 1353 | |
ed1e77d3 | 1354 | static void triggerTierUpNowCommon(ExecState* exec, bool inLoop) |
81345200 A |
1355 | { |
1356 | VM* vm = &exec->vm(); | |
1357 | NativeCallFrameTracer tracer(vm, exec); | |
1358 | DeferGC deferGC(vm->heap); | |
1359 | CodeBlock* codeBlock = exec->codeBlock(); | |
1360 | ||
ed1e77d3 A |
1361 | if (codeBlock->jitType() != JITCode::DFGJIT) { |
1362 | dataLog("Unexpected code block in DFG->FTL tier-up: ", *codeBlock, "\n"); | |
1363 | RELEASE_ASSERT_NOT_REACHED(); | |
1364 | } | |
1365 | ||
81345200 A |
1366 | JITCode* jitCode = codeBlock->jitCode()->dfg(); |
1367 | ||
1368 | if (Options::verboseOSR()) { | |
1369 | dataLog( | |
1370 | *codeBlock, ": Entered triggerTierUpNow with executeCounter = ", | |
1371 | jitCode->tierUpCounter, "\n"); | |
1372 | } | |
ed1e77d3 A |
1373 | if (inLoop) |
1374 | jitCode->nestedTriggerIsSet = 1; | |
1375 | ||
81345200 A |
1376 | triggerFTLReplacementCompile(vm, codeBlock, jitCode); |
1377 | } | |
6fe7ccc8 | 1378 | |
ed1e77d3 A |
1379 | void JIT_OPERATION triggerTierUpNow(ExecState* exec) |
1380 | { | |
1381 | triggerTierUpNowCommon(exec, false); | |
1382 | } | |
1383 | ||
1384 | void JIT_OPERATION triggerTierUpNowInLoop(ExecState* exec) | |
1385 | { | |
1386 | triggerTierUpNowCommon(exec, true); | |
1387 | } | |
1388 | ||
81345200 A |
1389 | char* JIT_OPERATION triggerOSREntryNow( |
1390 | ExecState* exec, int32_t bytecodeIndex, int32_t streamIndex) | |
6fe7ccc8 | 1391 | { |
81345200 A |
1392 | VM* vm = &exec->vm(); |
1393 | NativeCallFrameTracer tracer(vm, exec); | |
1394 | DeferGC deferGC(vm->heap); | |
1395 | CodeBlock* codeBlock = exec->codeBlock(); | |
1396 | ||
ed1e77d3 A |
1397 | if (codeBlock->jitType() != JITCode::DFGJIT) { |
1398 | dataLog("Unexpected code block in DFG->FTL tier-up: ", *codeBlock, "\n"); | |
1399 | RELEASE_ASSERT_NOT_REACHED(); | |
1400 | } | |
1401 | ||
81345200 | 1402 | JITCode* jitCode = codeBlock->jitCode()->dfg(); |
ed1e77d3 | 1403 | jitCode->nestedTriggerIsSet = 0; |
81345200 A |
1404 | |
1405 | if (Options::verboseOSR()) { | |
1406 | dataLog( | |
ed1e77d3 | 1407 | *codeBlock, ": Entered triggerOSREntryNow with executeCounter = ", |
81345200 A |
1408 | jitCode->tierUpCounter, "\n"); |
1409 | } | |
1410 | ||
1411 | // - If we don't have an FTL code block, then try to compile one. | |
1412 | // - If we do have an FTL code block, then try to enter for a while. | |
1413 | // - If we couldn't enter for a while, then trigger OSR entry. | |
1414 | ||
1415 | triggerFTLReplacementCompile(vm, codeBlock, jitCode); | |
1416 | ||
1417 | if (!codeBlock->hasOptimizedReplacement()) | |
1418 | return 0; | |
1419 | ||
1420 | if (jitCode->osrEntryRetry < Options::ftlOSREntryRetryThreshold()) { | |
1421 | jitCode->osrEntryRetry++; | |
1422 | return 0; | |
1423 | } | |
1424 | ||
1425 | // It's time to try to compile code for OSR entry. | |
1426 | Worklist::State worklistState; | |
1427 | if (Worklist* worklist = existingGlobalFTLWorklistOrNull()) { | |
1428 | worklistState = worklist->completeAllReadyPlansForVM( | |
1429 | *vm, CompilationKey(codeBlock->baselineVersion(), FTLForOSREntryMode)); | |
1430 | } else | |
1431 | worklistState = Worklist::NotKnown; | |
1432 | ||
1433 | if (worklistState == Worklist::Compiling) | |
1434 | return 0; | |
1435 | ||
1436 | if (CodeBlock* entryBlock = jitCode->osrEntryBlock.get()) { | |
1437 | void* address = FTL::prepareOSREntry( | |
1438 | exec, codeBlock, entryBlock, bytecodeIndex, streamIndex); | |
1439 | if (address) | |
1440 | return static_cast<char*>(address); | |
1441 | ||
1442 | FTL::ForOSREntryJITCode* entryCode = entryBlock->jitCode()->ftlForOSREntry(); | |
1443 | entryCode->countEntryFailure(); | |
1444 | if (entryCode->entryFailureCount() < | |
1445 | Options::ftlOSREntryFailureCountForReoptimization()) | |
1446 | return 0; | |
1447 | ||
1448 | // OSR entry failed. Oh no! This implies that we need to retry. We retry | |
1449 | // without exponential backoff and we only do this for the entry code block. | |
ed1e77d3 | 1450 | jitCode->osrEntryBlock = nullptr; |
81345200 A |
1451 | jitCode->osrEntryRetry = 0; |
1452 | return 0; | |
1453 | } | |
1454 | ||
1455 | if (worklistState == Worklist::Compiled) { | |
1456 | // This means that compilation failed and we already set the thresholds. | |
1457 | if (Options::verboseOSR()) | |
1458 | dataLog("Code block ", *codeBlock, " was compiled but it doesn't have an optimized replacement.\n"); | |
1459 | return 0; | |
1460 | } | |
1461 | ||
1462 | // We aren't compiling and haven't compiled anything for OSR entry. So, try to compile | |
1463 | // something. | |
1464 | Operands<JSValue> mustHandleValues; | |
1465 | jitCode->reconstruct( | |
1466 | exec, codeBlock, CodeOrigin(bytecodeIndex), streamIndex, mustHandleValues); | |
1467 | RefPtr<CodeBlock> replacementCodeBlock = codeBlock->newReplacement(); | |
1468 | CompilationResult forEntryResult = compile( | |
1469 | *vm, replacementCodeBlock.get(), codeBlock, FTLForOSREntryMode, bytecodeIndex, | |
1470 | mustHandleValues, ToFTLForOSREntryDeferredCompilationCallback::create(codeBlock)); | |
1471 | ||
1472 | if (forEntryResult != CompilationSuccessful) { | |
1473 | ASSERT(forEntryResult == CompilationDeferred || replacementCodeBlock->hasOneRef()); | |
1474 | return 0; | |
1475 | } | |
1476 | ||
1477 | // It's possible that the for-entry compile already succeeded. In that case OSR | |
1478 | // entry will succeed unless we ran out of stack. It's not clear what we should do. | |
1479 | // We signal to try again after a while if that happens. | |
1480 | void* address = FTL::prepareOSREntry( | |
1481 | exec, codeBlock, jitCode->osrEntryBlock.get(), bytecodeIndex, streamIndex); | |
1482 | return static_cast<char*>(address); | |
6fe7ccc8 | 1483 | } |
81345200 | 1484 | #endif // ENABLE(FTL_JIT) |
6fe7ccc8 | 1485 | |
81345200 A |
1486 | } // extern "C" |
1487 | } } // namespace JSC::DFG | |
1488 | ||
1489 | #endif // ENABLE(DFG_JIT) | |
6fe7ccc8 | 1490 | |
93a37866 | 1491 | #endif // ENABLE(JIT) |