1 | /* |
2 | * Copyright (C) 2011-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 | * 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 "CommonSlowPaths.h" |
28 | |
29 | #include "ArithProfile.h" |
30 | #include "ArrayConstructor.h" |
31 | #include "BuiltinNames.h" |
32 | #include "BytecodeStructs.h" |
33 | #include "CallFrame.h" |
34 | #include "ClonedArguments.h" |
35 | #include "CodeProfiling.h" |
36 | #include "DefinePropertyAttributes.h" |
37 | #include "DirectArguments.h" |
38 | #include "Error.h" |
39 | #include "ErrorHandlingScope.h" |
40 | #include "ExceptionFuzz.h" |
41 | #include "FrameTracers.h" |
42 | #include "GetterSetter.h" |
43 | #include "HostCallReturnValue.h" |
44 | #include "ICStats.h" |
45 | #include "Interpreter.h" |
46 | #include "IteratorOperations.h" |
47 | #include "JIT.h" |
48 | #include "JSArrayInlines.h" |
49 | #include "JSAsyncGenerator.h" |
50 | #include "JSCInlines.h" |
51 | #include "JSCJSValue.h" |
52 | #include "JSFixedArray.h" |
53 | #include "JSGlobalObjectFunctions.h" |
54 | #include "JSImmutableButterfly.h" |
55 | #include "JSInternalPromise.h" |
56 | #include "JSInternalPromiseConstructor.h" |
57 | #include "JSLexicalEnvironment.h" |
58 | #include "JSPromiseConstructor.h" |
59 | #include "JSPropertyNameEnumerator.h" |
60 | #include "JSString.h" |
61 | #include "JSWithScope.h" |
62 | #include "LLIntCommon.h" |
63 | #include "LLIntExceptions.h" |
64 | #include "LowLevelInterpreter.h" |
65 | #include "MathCommon.h" |
66 | #include "ObjectConstructor.h" |
67 | #include "OpcodeInlines.h" |
68 | #include "ScopedArguments.h" |
69 | #include "StructureRareDataInlines.h" |
70 | #include "ThunkGenerators.h" |
71 | #include "TypeProfilerLog.h" |
72 | #include <wtf/StringPrintStream.h> |
73 | #include <wtf/Variant.h> |
74 | |
75 | namespace JSC { |
76 | |
77 | #define BEGIN_NO_SET_PC() \ |
78 | CodeBlock* codeBlock = callFrame->codeBlock(); \ |
79 | JSGlobalObject* globalObject = codeBlock->globalObject(); \ |
80 | VM& vm = codeBlock->vm(); \ |
81 | SlowPathFrameTracer tracer(vm, callFrame); \ |
82 | auto throwScope = DECLARE_THROW_SCOPE(vm); \ |
83 | UNUSED_PARAM(throwScope) |
84 | |
85 | #ifndef NDEBUG |
86 | #define SET_PC_FOR_STUBS() do { \ |
87 | codeBlock->bytecodeOffset(pc); \ |
88 | callFrame->setCurrentVPC(pc); \ |
89 | } while (false) |
90 | #else |
91 | #define SET_PC_FOR_STUBS() do { \ |
92 | callFrame->setCurrentVPC(pc); \ |
93 | } while (false) |
94 | #endif |
95 | |
96 | #define RETURN_TO_THROW(pc) pc = LLInt::returnToThrow(vm) |
97 | |
98 | #define BEGIN() \ |
99 | BEGIN_NO_SET_PC(); \ |
100 | SET_PC_FOR_STUBS() |
101 | |
102 | #define GET(operand) (callFrame->uncheckedR(operand.offset())) |
103 | #define GET_C(operand) (callFrame->r(operand.offset())) |
104 | |
105 | #define RETURN_TWO(first, second) do { \ |
106 | return encodeResult(first, second); \ |
107 | } while (false) |
108 | |
109 | #define END_IMPL() RETURN_TWO(pc, callFrame) |
110 | |
111 | #define THROW(exceptionToThrow) do { \ |
112 | throwException(globalObject, throwScope, exceptionToThrow); \ |
113 | RETURN_TO_THROW(pc); \ |
114 | END_IMPL(); \ |
115 | } while (false) |
116 | |
117 | #define CHECK_EXCEPTION() do { \ |
118 | doExceptionFuzzingIfEnabled(globalObject, throwScope, "CommonSlowPaths", pc); \ |
119 | if (UNLIKELY(throwScope.exception())) { \ |
120 | RETURN_TO_THROW(pc); \ |
121 | END_IMPL(); \ |
122 | } \ |
123 | } while (false) |
124 | |
125 | #define END() do { \ |
126 | CHECK_EXCEPTION(); \ |
127 | END_IMPL(); \ |
128 | } while (false) |
129 | |
130 | #define BRANCH(condition) do { \ |
131 | bool bCondition = (condition); \ |
132 | CHECK_EXCEPTION(); \ |
133 | if (bCondition) \ |
134 | pc = bytecode.m_targetLabel \ |
135 | ? reinterpret_cast<const Instruction*>(reinterpret_cast<const uint8_t*>(pc) + bytecode.m_targetLabel) \ |
136 | : codeBlock->outOfLineJumpTarget(pc); \ |
137 | else \ |
138 | pc = reinterpret_cast<const Instruction*>(reinterpret_cast<const uint8_t*>(pc) + pc->size()); \ |
139 | END_IMPL(); \ |
140 | } while (false) |
141 | |
142 | #define RETURN_WITH_PROFILING_CUSTOM(result__, value__, profilingAction__) do { \ |
143 | JSValue returnValue__ = (value__); \ |
144 | CHECK_EXCEPTION(); \ |
145 | GET(result__) = returnValue__; \ |
146 | profilingAction__; \ |
147 | END_IMPL(); \ |
148 | } while (false) |
149 | |
150 | #define RETURN_WITH_PROFILING(value__, profilingAction__) RETURN_WITH_PROFILING_CUSTOM(bytecode.m_dst, value__, profilingAction__) |
151 | |
152 | #define RETURN(value) \ |
153 | RETURN_WITH_PROFILING(value, { }) |
154 | |
155 | #define RETURN_PROFILED(value__) \ |
156 | RETURN_WITH_PROFILING(value__, PROFILE_VALUE(returnValue__)) |
157 | |
158 | #define PROFILE_VALUE(value) do { \ |
159 | bytecode.metadata(codeBlock).m_profile.m_buckets[0] = JSValue::encode(value); \ |
160 | } while (false) |
161 | |
162 | static void throwArityCheckStackOverflowError(JSGlobalObject* globalObject, ThrowScope& scope) |
163 | { |
164 | JSObject* error = createStackOverflowError(globalObject); |
165 | throwException(globalObject, scope, error); |
166 | #if LLINT_TRACING |
167 | if (UNLIKELY(Options::traceLLIntSlowPath())) |
168 | dataLog("Throwing exception " , JSValue(scope.exception()), ".\n" ); |
169 | #endif |
170 | } |
171 | |
172 | SLOW_PATH_DECL(slow_path_call_arityCheck) |
173 | { |
174 | BEGIN(); |
175 | int slotsToAdd = CommonSlowPaths::arityCheckFor(vm, callFrame, CodeForCall); |
176 | if (UNLIKELY(slotsToAdd < 0)) { |
177 | CodeBlock* codeBlock = CommonSlowPaths::codeBlockFromCallFrameCallee(callFrame, CodeForCall); |
178 | callFrame->convertToStackOverflowFrame(vm, codeBlock); |
179 | SlowPathFrameTracer tracer(vm, callFrame); |
180 | ErrorHandlingScope errorScope(vm); |
181 | throwScope.release(); |
182 | throwArityCheckStackOverflowError(globalObject, throwScope); |
183 | RETURN_TWO(bitwise_cast<void*>(static_cast<uintptr_t>(1)), callFrame); |
184 | } |
185 | RETURN_TWO(0, bitwise_cast<void*>(static_cast<uintptr_t>(slotsToAdd))); |
186 | } |
187 | |
188 | SLOW_PATH_DECL(slow_path_construct_arityCheck) |
189 | { |
190 | BEGIN(); |
191 | int slotsToAdd = CommonSlowPaths::arityCheckFor(vm, callFrame, CodeForConstruct); |
192 | if (UNLIKELY(slotsToAdd < 0)) { |
193 | CodeBlock* codeBlock = CommonSlowPaths::codeBlockFromCallFrameCallee(callFrame, CodeForConstruct); |
194 | callFrame->convertToStackOverflowFrame(vm, codeBlock); |
195 | SlowPathFrameTracer tracer(vm, callFrame); |
196 | ErrorHandlingScope errorScope(vm); |
197 | throwArityCheckStackOverflowError(globalObject, throwScope); |
198 | RETURN_TWO(bitwise_cast<void*>(static_cast<uintptr_t>(1)), callFrame); |
199 | } |
200 | RETURN_TWO(0, bitwise_cast<void*>(static_cast<uintptr_t>(slotsToAdd))); |
201 | } |
202 | |
203 | SLOW_PATH_DECL(slow_path_create_direct_arguments) |
204 | { |
205 | BEGIN(); |
206 | auto bytecode = pc->as<OpCreateDirectArguments>(); |
207 | RETURN(DirectArguments::createByCopying(globalObject, callFrame)); |
208 | } |
209 | |
210 | SLOW_PATH_DECL(slow_path_create_scoped_arguments) |
211 | { |
212 | BEGIN(); |
213 | auto bytecode = pc->as<OpCreateScopedArguments>(); |
214 | JSLexicalEnvironment* scope = jsCast<JSLexicalEnvironment*>(GET(bytecode.m_scope).jsValue()); |
215 | ScopedArgumentsTable* table = scope->symbolTable()->arguments(); |
216 | RETURN(ScopedArguments::createByCopying(globalObject, callFrame, table, scope)); |
217 | } |
218 | |
219 | SLOW_PATH_DECL(slow_path_create_cloned_arguments) |
220 | { |
221 | BEGIN(); |
222 | auto bytecode = pc->as<OpCreateClonedArguments>(); |
223 | RETURN(ClonedArguments::createWithMachineFrame(globalObject, callFrame, ArgumentsMode::Cloned)); |
224 | } |
225 | |
226 | SLOW_PATH_DECL(slow_path_create_this) |
227 | { |
228 | BEGIN(); |
229 | auto bytecode = pc->as<OpCreateThis>(); |
230 | JSObject* result; |
231 | JSObject* constructorAsObject = asObject(GET(bytecode.m_callee).jsValue()); |
232 | JSFunction* constructor = jsDynamicCast<JSFunction*>(vm, constructorAsObject); |
233 | if (constructor && constructor->canUseAllocationProfile()) { |
234 | WriteBarrier<JSCell>& cachedCallee = bytecode.metadata(codeBlock).m_cachedCallee; |
235 | if (!cachedCallee) |
236 | cachedCallee.set(vm, codeBlock, constructor); |
237 | else if (cachedCallee.unvalidatedGet() != JSCell::seenMultipleCalleeObjects() && cachedCallee.get() != constructor) |
238 | cachedCallee.setWithoutWriteBarrier(JSCell::seenMultipleCalleeObjects()); |
239 | |
240 | size_t inlineCapacity = bytecode.m_inlineCapacity; |
241 | ObjectAllocationProfileWithPrototype* allocationProfile = constructor->ensureRareDataAndAllocationProfile(globalObject, inlineCapacity)->objectAllocationProfile(); |
242 | throwScope.releaseAssertNoException(); |
243 | Structure* structure = allocationProfile->structure(); |
244 | result = constructEmptyObject(vm, structure); |
245 | if (structure->hasPolyProto()) { |
246 | JSObject* prototype = allocationProfile->prototype(); |
247 | ASSERT(prototype == constructor->prototypeForConstruction(vm, globalObject)); |
248 | result->putDirect(vm, knownPolyProtoOffset, prototype); |
249 | prototype->didBecomePrototype(); |
250 | ASSERT_WITH_MESSAGE(!hasIndexedProperties(result->indexingType()), "We rely on JSFinalObject not starting out with an indexing type otherwise we would potentially need to convert to slow put storage" ); |
251 | } |
252 | } else { |
253 | // http://ecma-international.org/ecma-262/6.0/#sec-ordinarycreatefromconstructor |
254 | JSValue proto = constructorAsObject->get(globalObject, vm.propertyNames->prototype); |
255 | CHECK_EXCEPTION(); |
256 | if (proto.isObject()) |
257 | result = constructEmptyObject(globalObject, asObject(proto)); |
258 | else |
259 | result = constructEmptyObject(globalObject); |
260 | } |
261 | RETURN(result); |
262 | } |
263 | |
264 | SLOW_PATH_DECL(slow_path_create_promise) |
265 | { |
266 | BEGIN(); |
267 | auto bytecode = pc->as<OpCreatePromise>(); |
268 | JSObject* constructorAsObject = asObject(GET(bytecode.m_callee).jsValue()); |
269 | |
270 | JSPromise* result = nullptr; |
271 | if (bytecode.m_isInternalPromise) { |
272 | Structure* structure = InternalFunction::createSubclassStructure(globalObject, globalObject->internalPromiseConstructor(), constructorAsObject, globalObject->internalPromiseStructure()); |
273 | CHECK_EXCEPTION(); |
274 | result = JSInternalPromise::create(vm, structure); |
275 | } else { |
276 | Structure* structure = InternalFunction::createSubclassStructure(globalObject, globalObject->promiseConstructor(), constructorAsObject, globalObject->promiseStructure()); |
277 | CHECK_EXCEPTION(); |
278 | result = JSPromise::create(vm, structure); |
279 | } |
280 | |
281 | JSFunction* constructor = jsDynamicCast<JSFunction*>(vm, constructorAsObject); |
282 | if (constructor && constructor->canUseAllocationProfile()) { |
283 | WriteBarrier<JSCell>& cachedCallee = bytecode.metadata(codeBlock).m_cachedCallee; |
284 | if (!cachedCallee) |
285 | cachedCallee.set(vm, codeBlock, constructor); |
286 | else if (cachedCallee.unvalidatedGet() != JSCell::seenMultipleCalleeObjects() && cachedCallee.get() != constructor) |
287 | cachedCallee.setWithoutWriteBarrier(JSCell::seenMultipleCalleeObjects()); |
288 | } |
289 | RETURN(result); |
290 | } |
291 | |
292 | SLOW_PATH_DECL(slow_path_new_promise) |
293 | { |
294 | BEGIN(); |
295 | auto bytecode = pc->as<OpNewPromise>(); |
296 | JSPromise* result = nullptr; |
297 | if (bytecode.m_isInternalPromise) |
298 | result = JSInternalPromise::create(vm, globalObject->internalPromiseStructure()); |
299 | else |
300 | result = JSPromise::create(vm, globalObject->promiseStructure()); |
301 | RETURN(result); |
302 | } |
303 | |
304 | template<typename JSClass, typename Bytecode> |
305 | static JSClass* createInternalFieldObject(JSGlobalObject* globalObject, VM& vm, CodeBlock* codeBlock, const Bytecode& bytecode, JSObject* constructorAsObject, Structure* baseStructure) |
306 | { |
307 | auto scope = DECLARE_THROW_SCOPE(vm); |
308 | |
309 | Structure* structure = InternalFunction::createSubclassStructure(globalObject, nullptr, constructorAsObject, baseStructure); |
310 | RETURN_IF_EXCEPTION(scope, nullptr); |
311 | JSClass* result = JSClass::create(vm, structure); |
312 | |
313 | JSFunction* constructor = jsDynamicCast<JSFunction*>(vm, constructorAsObject); |
314 | if (constructor && constructor->canUseAllocationProfile()) { |
315 | WriteBarrier<JSCell>& cachedCallee = bytecode.metadata(codeBlock).m_cachedCallee; |
316 | if (!cachedCallee) |
317 | cachedCallee.set(vm, codeBlock, constructor); |
318 | else if (cachedCallee.unvalidatedGet() != JSCell::seenMultipleCalleeObjects() && cachedCallee.get() != constructor) |
319 | cachedCallee.setWithoutWriteBarrier(JSCell::seenMultipleCalleeObjects()); |
320 | } |
321 | RELEASE_AND_RETURN(scope, result); |
322 | } |
323 | |
324 | SLOW_PATH_DECL(slow_path_create_generator) |
325 | { |
326 | BEGIN(); |
327 | auto bytecode = pc->as<OpCreateGenerator>(); |
328 | RETURN(createInternalFieldObject<JSGenerator>(globalObject, vm, codeBlock, bytecode, asObject(GET(bytecode.m_callee).jsValue()), globalObject->generatorStructure())); |
329 | } |
330 | |
331 | SLOW_PATH_DECL(slow_path_create_async_generator) |
332 | { |
333 | BEGIN(); |
334 | auto bytecode = pc->as<OpCreateAsyncGenerator>(); |
335 | RETURN(createInternalFieldObject<JSAsyncGenerator>(globalObject, vm, codeBlock, bytecode, asObject(GET(bytecode.m_callee).jsValue()), globalObject->asyncGeneratorStructure())); |
336 | } |
337 | |
338 | SLOW_PATH_DECL(slow_path_new_generator) |
339 | { |
340 | BEGIN(); |
341 | auto bytecode = pc->as<OpNewGenerator>(); |
342 | JSGenerator* result = JSGenerator::create(vm, globalObject->generatorStructure()); |
343 | RETURN(result); |
344 | } |
345 | |
346 | SLOW_PATH_DECL(slow_path_to_this) |
347 | { |
348 | BEGIN(); |
349 | auto bytecode = pc->as<OpToThis>(); |
350 | auto& metadata = bytecode.metadata(codeBlock); |
351 | JSValue v1 = GET(bytecode.m_srcDst).jsValue(); |
352 | if (v1.isCell()) { |
353 | StructureID myStructureID = v1.asCell()->structureID(); |
354 | StructureID otherStructureID = metadata.m_cachedStructureID; |
355 | if (myStructureID != otherStructureID) { |
356 | if (otherStructureID) |
357 | metadata.m_toThisStatus = ToThisConflicted; |
358 | metadata.m_cachedStructureID = myStructureID; |
359 | vm.heap.writeBarrier(codeBlock, vm.getStructure(myStructureID)); |
360 | } |
361 | } else { |
362 | metadata.m_toThisStatus = ToThisConflicted; |
363 | metadata.m_cachedStructureID = 0; |
364 | } |
365 | // Note: We only need to do this value profiling here on the slow path. The fast path |
366 | // just returns the input to to_this if the structure check succeeds. If the structure |
367 | // check succeeds, doing value profiling here is equivalent to doing it with a potentially |
368 | // different object that still has the same structure on the fast path since it'll produce |
369 | // the same SpeculatedType. Therefore, we don't need to worry about value profiling on the |
370 | // fast path. |
371 | auto value = v1.toThis(globalObject, codeBlock->isStrictMode() ? StrictMode : NotStrictMode); |
372 | RETURN_WITH_PROFILING_CUSTOM(bytecode.m_srcDst, value, PROFILE_VALUE(value)); |
373 | } |
374 | |
375 | SLOW_PATH_DECL(slow_path_throw_tdz_error) |
376 | { |
377 | BEGIN(); |
378 | THROW(createTDZError(globalObject)); |
379 | } |
380 | |
381 | SLOW_PATH_DECL(slow_path_check_tdz) |
382 | { |
383 | BEGIN(); |
384 | THROW(createTDZError(globalObject)); |
385 | } |
386 | |
387 | SLOW_PATH_DECL(slow_path_throw_strict_mode_readonly_property_write_error) |
388 | { |
389 | BEGIN(); |
390 | THROW(createTypeError(globalObject, ReadonlyPropertyWriteError)); |
391 | } |
392 | |
393 | SLOW_PATH_DECL(slow_path_not) |
394 | { |
395 | BEGIN(); |
396 | auto bytecode = pc->as<OpNot>(); |
397 | RETURN(jsBoolean(!GET_C(bytecode.m_operand).jsValue().toBoolean(globalObject))); |
398 | } |
399 | |
400 | SLOW_PATH_DECL(slow_path_eq) |
401 | { |
402 | BEGIN(); |
403 | auto bytecode = pc->as<OpEq>(); |
404 | RETURN(jsBoolean(JSValue::equal(globalObject, GET_C(bytecode.m_lhs).jsValue(), GET_C(bytecode.m_rhs).jsValue()))); |
405 | } |
406 | |
407 | SLOW_PATH_DECL(slow_path_neq) |
408 | { |
409 | BEGIN(); |
410 | auto bytecode = pc->as<OpNeq>(); |
411 | RETURN(jsBoolean(!JSValue::equal(globalObject, GET_C(bytecode.m_lhs).jsValue(), GET_C(bytecode.m_rhs).jsValue()))); |
412 | } |
413 | |
414 | SLOW_PATH_DECL(slow_path_stricteq) |
415 | { |
416 | BEGIN(); |
417 | auto bytecode = pc->as<OpStricteq>(); |
418 | RETURN(jsBoolean(JSValue::strictEqual(globalObject, GET_C(bytecode.m_lhs).jsValue(), GET_C(bytecode.m_rhs).jsValue()))); |
419 | } |
420 | |
421 | SLOW_PATH_DECL(slow_path_nstricteq) |
422 | { |
423 | BEGIN(); |
424 | auto bytecode = pc->as<OpNstricteq>(); |
425 | RETURN(jsBoolean(!JSValue::strictEqual(globalObject, GET_C(bytecode.m_lhs).jsValue(), GET_C(bytecode.m_rhs).jsValue()))); |
426 | } |
427 | |
428 | SLOW_PATH_DECL(slow_path_less) |
429 | { |
430 | BEGIN(); |
431 | auto bytecode = pc->as<OpLess>(); |
432 | RETURN(jsBoolean(jsLess<true>(globalObject, GET_C(bytecode.m_lhs).jsValue(), GET_C(bytecode.m_rhs).jsValue()))); |
433 | } |
434 | |
435 | SLOW_PATH_DECL(slow_path_lesseq) |
436 | { |
437 | BEGIN(); |
438 | auto bytecode = pc->as<OpLesseq>(); |
439 | RETURN(jsBoolean(jsLessEq<true>(globalObject, GET_C(bytecode.m_lhs).jsValue(), GET_C(bytecode.m_rhs).jsValue()))); |
440 | } |
441 | |
442 | SLOW_PATH_DECL(slow_path_greater) |
443 | { |
444 | BEGIN(); |
445 | auto bytecode = pc->as<OpGreater>(); |
446 | RETURN(jsBoolean(jsLess<false>(globalObject, GET_C(bytecode.m_rhs).jsValue(), GET_C(bytecode.m_lhs).jsValue()))); |
447 | } |
448 | |
449 | SLOW_PATH_DECL(slow_path_greatereq) |
450 | { |
451 | BEGIN(); |
452 | auto bytecode = pc->as<OpGreatereq>(); |
453 | RETURN(jsBoolean(jsLessEq<false>(globalObject, GET_C(bytecode.m_rhs).jsValue(), GET_C(bytecode.m_lhs).jsValue()))); |
454 | } |
455 | |
456 | SLOW_PATH_DECL(slow_path_inc) |
457 | { |
458 | BEGIN(); |
459 | auto bytecode = pc->as<OpInc>(); |
460 | JSValue argument = GET_C(bytecode.m_srcDst).jsValue(); |
461 | Variant<JSBigInt*, double> resultVariant = argument.toNumeric(globalObject); |
462 | CHECK_EXCEPTION(); |
463 | JSValue result; |
464 | if (WTF::holds_alternative<JSBigInt*>(resultVariant)) |
465 | result = JSBigInt::inc(globalObject, WTF::get<JSBigInt*>(resultVariant)); |
466 | else |
467 | result = jsNumber(WTF::get<double>(resultVariant) + 1); |
468 | RETURN_WITH_PROFILING_CUSTOM(bytecode.m_srcDst, result, { }); |
469 | } |
470 | |
471 | SLOW_PATH_DECL(slow_path_dec) |
472 | { |
473 | BEGIN(); |
474 | auto bytecode = pc->as<OpDec>(); |
475 | JSValue argument = GET_C(bytecode.m_srcDst).jsValue(); |
476 | Variant<JSBigInt*, double> resultVariant = argument.toNumeric(globalObject); |
477 | CHECK_EXCEPTION(); |
478 | JSValue result; |
479 | if (WTF::holds_alternative<JSBigInt*>(resultVariant)) |
480 | result = JSBigInt::dec(globalObject, WTF::get<JSBigInt*>(resultVariant)); |
481 | else |
482 | result = jsNumber(WTF::get<double>(resultVariant) - 1); |
483 | RETURN_WITH_PROFILING_CUSTOM(bytecode.m_srcDst, result, { }); |
484 | } |
485 | |
486 | SLOW_PATH_DECL(slow_path_to_string) |
487 | { |
488 | BEGIN(); |
489 | auto bytecode = pc->as<OpToString>(); |
490 | RETURN(GET_C(bytecode.m_operand).jsValue().toString(globalObject)); |
491 | } |
492 | |
493 | #if ENABLE(JIT) |
494 | static void updateArithProfileForUnaryArithOp(OpNegate::Metadata& metadata, JSValue result, JSValue operand) |
495 | { |
496 | UnaryArithProfile& profile = metadata.m_arithProfile; |
497 | profile.observeArg(operand); |
498 | ASSERT(result.isNumber() || result.isBigInt()); |
499 | if (result.isNumber()) { |
500 | if (!result.isInt32()) { |
501 | if (operand.isInt32()) |
502 | profile.setObservedInt32Overflow(); |
503 | |
504 | double doubleVal = result.asNumber(); |
505 | if (!doubleVal && std::signbit(doubleVal)) |
506 | profile.setObservedNegZeroDouble(); |
507 | else { |
508 | profile.setObservedNonNegZeroDouble(); |
509 | |
510 | // The Int52 overflow check here intentionally omits 1ll << 51 as a valid negative Int52 value. |
511 | // Therefore, we will get a false positive if the result is that value. This is intentionally |
512 | // done to simplify the checking algorithm. |
513 | static const int64_t int52OverflowPoint = (1ll << 51); |
514 | int64_t int64Val = static_cast<int64_t>(std::abs(doubleVal)); |
515 | if (int64Val >= int52OverflowPoint) |
516 | profile.setObservedInt52Overflow(); |
517 | } |
518 | } |
519 | } else if (result.isBigInt()) |
520 | profile.setObservedBigInt(); |
521 | else |
522 | profile.setObservedNonNumeric(); |
523 | } |
524 | #else |
525 | static void updateArithProfileForUnaryArithOp(OpNegate::Metadata&, JSValue, JSValue) { } |
526 | #endif |
527 | |
528 | SLOW_PATH_DECL(slow_path_negate) |
529 | { |
530 | BEGIN(); |
531 | auto bytecode = pc->as<OpNegate>(); |
532 | auto& metadata = bytecode.metadata(codeBlock); |
533 | JSValue operand = GET_C(bytecode.m_operand).jsValue(); |
534 | JSValue primValue = operand.toPrimitive(globalObject, PreferNumber); |
535 | CHECK_EXCEPTION(); |
536 | |
537 | if (primValue.isBigInt()) { |
538 | JSBigInt* result = JSBigInt::unaryMinus(vm, asBigInt(primValue)); |
539 | RETURN_WITH_PROFILING(result, { |
540 | updateArithProfileForUnaryArithOp(metadata, result, operand); |
541 | }); |
542 | } |
543 | |
544 | JSValue result = jsNumber(-primValue.toNumber(globalObject)); |
545 | CHECK_EXCEPTION(); |
546 | RETURN_WITH_PROFILING(result, { |
547 | updateArithProfileForUnaryArithOp(metadata, result, operand); |
548 | }); |
549 | } |
550 | |
551 | #if ENABLE(DFG_JIT) |
552 | static void updateArithProfileForBinaryArithOp(JSGlobalObject*, CodeBlock* codeBlock, const Instruction* pc, JSValue result, JSValue left, JSValue right) |
553 | { |
554 | BinaryArithProfile& profile = *codeBlock->binaryArithProfileForPC(pc); |
555 | |
556 | if (result.isNumber()) { |
557 | if (!result.isInt32()) { |
558 | if (left.isInt32() && right.isInt32()) |
559 | profile.setObservedInt32Overflow(); |
560 | |
561 | double doubleVal = result.asNumber(); |
562 | if (!doubleVal && std::signbit(doubleVal)) |
563 | profile.setObservedNegZeroDouble(); |
564 | else { |
565 | profile.setObservedNonNegZeroDouble(); |
566 | |
567 | // The Int52 overflow check here intentionally omits 1ll << 51 as a valid negative Int52 value. |
568 | // Therefore, we will get a false positive if the result is that value. This is intentionally |
569 | // done to simplify the checking algorithm. |
570 | static const int64_t int52OverflowPoint = (1ll << 51); |
571 | int64_t int64Val = static_cast<int64_t>(std::abs(doubleVal)); |
572 | if (int64Val >= int52OverflowPoint) |
573 | profile.setObservedInt52Overflow(); |
574 | } |
575 | } |
576 | } else if (result.isBigInt()) |
577 | profile.setObservedBigInt(); |
578 | else |
579 | profile.setObservedNonNumeric(); |
580 | } |
581 | #else |
582 | static void updateArithProfileForBinaryArithOp(JSGlobalObject*, CodeBlock*, const Instruction*, JSValue, JSValue, JSValue) { } |
583 | #endif |
584 | |
585 | SLOW_PATH_DECL(slow_path_to_number) |
586 | { |
587 | BEGIN(); |
588 | auto bytecode = pc->as<OpToNumber>(); |
589 | JSValue argument = GET_C(bytecode.m_operand).jsValue(); |
590 | JSValue result = jsNumber(argument.toNumber(globalObject)); |
591 | RETURN_PROFILED(result); |
592 | } |
593 | |
594 | SLOW_PATH_DECL(slow_path_to_numeric) |
595 | { |
596 | BEGIN(); |
597 | auto bytecode = pc->as<OpToNumeric>(); |
598 | JSValue argument = GET_C(bytecode.m_operand).jsValue(); |
599 | Variant<JSBigInt*, double> resultVariant = argument.toNumeric(globalObject); |
600 | CHECK_EXCEPTION(); |
601 | JSValue result; |
602 | if (WTF::holds_alternative<JSBigInt*>(resultVariant)) |
603 | result = WTF::get<JSBigInt*>(resultVariant); |
604 | else |
605 | result = jsNumber(WTF::get<double>(resultVariant)); |
606 | RETURN_PROFILED(result); |
607 | } |
608 | |
609 | SLOW_PATH_DECL(slow_path_to_object) |
610 | { |
611 | BEGIN(); |
612 | auto bytecode = pc->as<OpToObject>(); |
613 | JSValue argument = GET_C(bytecode.m_operand).jsValue(); |
614 | if (UNLIKELY(argument.isUndefinedOrNull())) { |
615 | const Identifier& ident = codeBlock->identifier(bytecode.m_message); |
616 | if (!ident.isEmpty()) |
617 | THROW(createTypeError(globalObject, ident.impl())); |
618 | } |
619 | JSObject* result = argument.toObject(globalObject); |
620 | RETURN_PROFILED(result); |
621 | } |
622 | |
623 | SLOW_PATH_DECL(slow_path_add) |
624 | { |
625 | BEGIN(); |
626 | auto bytecode = pc->as<OpAdd>(); |
627 | JSValue v1 = GET_C(bytecode.m_lhs).jsValue(); |
628 | JSValue v2 = GET_C(bytecode.m_rhs).jsValue(); |
629 | |
630 | BinaryArithProfile& arithProfile = *codeBlock->binaryArithProfileForPC(pc); |
631 | arithProfile.observeLHSAndRHS(v1, v2); |
632 | |
633 | JSValue result = jsAdd(globalObject, v1, v2); |
634 | |
635 | RETURN_WITH_PROFILING(result, { |
636 | updateArithProfileForBinaryArithOp(globalObject, codeBlock, pc, result, v1, v2); |
637 | }); |
638 | } |
639 | |
640 | // The following arithmetic and bitwise operations need to be sure to run |
641 | // toNumber() on their operands in order. (A call to toNumber() is idempotent |
642 | // if an exception is already set on the CallFrame.) |
643 | |
644 | SLOW_PATH_DECL(slow_path_mul) |
645 | { |
646 | BEGIN(); |
647 | auto bytecode = pc->as<OpMul>(); |
648 | JSValue left = GET_C(bytecode.m_lhs).jsValue(); |
649 | JSValue right = GET_C(bytecode.m_rhs).jsValue(); |
650 | JSValue result = jsMul(globalObject, left, right); |
651 | CHECK_EXCEPTION(); |
652 | RETURN_WITH_PROFILING(result, { |
653 | updateArithProfileForBinaryArithOp(globalObject, codeBlock, pc, result, left, right); |
654 | }); |
655 | } |
656 | |
657 | SLOW_PATH_DECL(slow_path_sub) |
658 | { |
659 | BEGIN(); |
660 | auto bytecode = pc->as<OpSub>(); |
661 | JSValue left = GET_C(bytecode.m_lhs).jsValue(); |
662 | JSValue right = GET_C(bytecode.m_rhs).jsValue(); |
663 | auto leftNumeric = left.toNumeric(globalObject); |
664 | CHECK_EXCEPTION(); |
665 | auto rightNumeric = right.toNumeric(globalObject); |
666 | CHECK_EXCEPTION(); |
667 | |
668 | if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) { |
669 | if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) { |
670 | JSBigInt* result = JSBigInt::sub(globalObject, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric)); |
671 | CHECK_EXCEPTION(); |
672 | RETURN_WITH_PROFILING(result, { |
673 | updateArithProfileForBinaryArithOp(globalObject, codeBlock, pc, result, left, right); |
674 | }); |
675 | } |
676 | |
677 | THROW(createTypeError(globalObject, "Invalid mix of BigInt and other type in subtraction." )); |
678 | } |
679 | |
680 | JSValue result = jsNumber(WTF::get<double>(leftNumeric) - WTF::get<double>(rightNumeric)); |
681 | RETURN_WITH_PROFILING(result, { |
682 | updateArithProfileForBinaryArithOp(globalObject, codeBlock, pc, result, left, right); |
683 | }); |
684 | } |
685 | |
686 | SLOW_PATH_DECL(slow_path_div) |
687 | { |
688 | BEGIN(); |
689 | auto bytecode = pc->as<OpDiv>(); |
690 | JSValue left = GET_C(bytecode.m_lhs).jsValue(); |
691 | JSValue right = GET_C(bytecode.m_rhs).jsValue(); |
692 | auto leftNumeric = left.toNumeric(globalObject); |
693 | CHECK_EXCEPTION(); |
694 | auto rightNumeric = right.toNumeric(globalObject); |
695 | CHECK_EXCEPTION(); |
696 | |
697 | if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) { |
698 | if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) { |
699 | JSBigInt* result = JSBigInt::divide(globalObject, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric)); |
700 | CHECK_EXCEPTION(); |
701 | RETURN_WITH_PROFILING(result, { |
702 | updateArithProfileForBinaryArithOp(globalObject, codeBlock, pc, result, left, right); |
703 | }); |
704 | } |
705 | |
706 | THROW(createTypeError(globalObject, "Invalid mix of BigInt and other type in division." )); |
707 | } |
708 | |
709 | double a = WTF::get<double>(leftNumeric); |
710 | double b = WTF::get<double>(rightNumeric); |
711 | JSValue result = jsNumber(a / b); |
712 | RETURN_WITH_PROFILING(result, { |
713 | updateArithProfileForBinaryArithOp(globalObject, codeBlock, pc, result, left, right); |
714 | }); |
715 | } |
716 | |
717 | SLOW_PATH_DECL(slow_path_mod) |
718 | { |
719 | BEGIN(); |
720 | auto bytecode = pc->as<OpMod>(); |
721 | JSValue left = GET_C(bytecode.m_lhs).jsValue(); |
722 | JSValue right = GET_C(bytecode.m_rhs).jsValue(); |
723 | auto leftNumeric = left.toNumeric(globalObject); |
724 | CHECK_EXCEPTION(); |
725 | auto rightNumeric = right.toNumeric(globalObject); |
726 | CHECK_EXCEPTION(); |
727 | |
728 | if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) { |
729 | if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) { |
730 | JSBigInt* result = JSBigInt::remainder(globalObject, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric)); |
731 | CHECK_EXCEPTION(); |
732 | RETURN(result); |
733 | } |
734 | |
735 | THROW(createTypeError(globalObject, "Invalid mix of BigInt and other type in remainder operation." )); |
736 | } |
737 | |
738 | double a = WTF::get<double>(leftNumeric); |
739 | double b = WTF::get<double>(rightNumeric); |
740 | RETURN(jsNumber(jsMod(a, b))); |
741 | } |
742 | |
743 | SLOW_PATH_DECL(slow_path_pow) |
744 | { |
745 | BEGIN(); |
746 | auto bytecode = pc->as<OpPow>(); |
747 | JSValue left = GET_C(bytecode.m_lhs).jsValue(); |
748 | JSValue right = GET_C(bytecode.m_rhs).jsValue(); |
749 | auto leftNumeric = left.toNumeric(globalObject); |
750 | CHECK_EXCEPTION(); |
751 | auto rightNumeric = right.toNumeric(globalObject); |
752 | CHECK_EXCEPTION(); |
753 | |
754 | if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) { |
755 | if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) { |
756 | JSBigInt* result = JSBigInt::exponentiate(globalObject, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric)); |
757 | CHECK_EXCEPTION(); |
758 | RETURN(result); |
759 | } |
760 | |
761 | THROW(createTypeError(globalObject, "Invalid mix of BigInt and other type in exponentiation operation." )); |
762 | } |
763 | |
764 | double a = WTF::get<double>(leftNumeric); |
765 | double b = WTF::get<double>(rightNumeric); |
766 | |
767 | RETURN(jsNumber(operationMathPow(a, b))); |
768 | } |
769 | |
770 | SLOW_PATH_DECL(slow_path_lshift) |
771 | { |
772 | BEGIN(); |
773 | auto bytecode = pc->as<OpLshift>(); |
774 | JSValue left = GET_C(bytecode.m_lhs).jsValue(); |
775 | JSValue right = GET_C(bytecode.m_rhs).jsValue(); |
776 | auto leftNumeric = left.toBigIntOrInt32(globalObject); |
777 | CHECK_EXCEPTION(); |
778 | auto rightNumeric = right.toBigIntOrInt32(globalObject); |
779 | CHECK_EXCEPTION(); |
780 | |
781 | if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) { |
782 | if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) { |
783 | JSBigInt* result = JSBigInt::leftShift(globalObject, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric)); |
784 | CHECK_EXCEPTION(); |
785 | RETURN_PROFILED(result); |
786 | } |
787 | |
788 | THROW(createTypeError(globalObject, "Invalid mix of BigInt and other type in left shift operation." )); |
789 | } |
790 | |
791 | RETURN_PROFILED(jsNumber(WTF::get<int32_t>(leftNumeric) << (WTF::get<int32_t>(rightNumeric) & 31))); |
792 | } |
793 | |
794 | SLOW_PATH_DECL(slow_path_rshift) |
795 | { |
796 | BEGIN(); |
797 | auto bytecode = pc->as<OpRshift>(); |
798 | JSValue left = GET_C(bytecode.m_lhs).jsValue(); |
799 | JSValue right = GET_C(bytecode.m_rhs).jsValue(); |
800 | auto leftNumeric = left.toBigIntOrInt32(globalObject); |
801 | CHECK_EXCEPTION(); |
802 | auto rightNumeric = right.toBigIntOrInt32(globalObject); |
803 | CHECK_EXCEPTION(); |
804 | |
805 | if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) { |
806 | if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) { |
807 | JSBigInt* result = JSBigInt::signedRightShift(globalObject, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric)); |
808 | CHECK_EXCEPTION(); |
809 | RETURN_PROFILED(result); |
810 | } |
811 | |
812 | THROW(createTypeError(globalObject, "Invalid mix of BigInt and other type in signed right shift operation."_s )); |
813 | } |
814 | |
815 | RETURN_PROFILED(jsNumber(WTF::get<int32_t>(leftNumeric) >> (WTF::get<int32_t>(rightNumeric) & 31))); |
816 | } |
817 | |
818 | SLOW_PATH_DECL(slow_path_urshift) |
819 | { |
820 | BEGIN(); |
821 | auto bytecode = pc->as<OpUrshift>(); |
822 | uint32_t a = GET_C(bytecode.m_lhs).jsValue().toUInt32(globalObject); |
823 | if (UNLIKELY(throwScope.exception())) |
824 | RETURN(JSValue()); |
825 | uint32_t b = GET_C(bytecode.m_rhs).jsValue().toUInt32(globalObject); |
826 | RETURN(jsNumber(static_cast<int32_t>(a >> (b & 31)))); |
827 | } |
828 | |
829 | SLOW_PATH_DECL(slow_path_unsigned) |
830 | { |
831 | BEGIN(); |
832 | auto bytecode = pc->as<OpUnsigned>(); |
833 | uint32_t a = GET_C(bytecode.m_operand).jsValue().toUInt32(globalObject); |
834 | RETURN(jsNumber(a)); |
835 | } |
836 | |
837 | SLOW_PATH_DECL(slow_path_bitnot) |
838 | { |
839 | BEGIN(); |
840 | auto bytecode = pc->as<OpBitnot>(); |
841 | auto operandNumeric = GET_C(bytecode.m_operand).jsValue().toBigIntOrInt32(globalObject); |
842 | CHECK_EXCEPTION(); |
843 | |
844 | if (WTF::holds_alternative<JSBigInt*>(operandNumeric)) { |
845 | JSBigInt* result = JSBigInt::bitwiseNot(globalObject, WTF::get<JSBigInt*>(operandNumeric)); |
846 | CHECK_EXCEPTION(); |
847 | RETURN_PROFILED(result); |
848 | } |
849 | |
850 | RETURN_PROFILED(jsNumber(~WTF::get<int32_t>(operandNumeric))); |
851 | } |
852 | |
853 | SLOW_PATH_DECL(slow_path_bitand) |
854 | { |
855 | BEGIN(); |
856 | auto bytecode = pc->as<OpBitand>(); |
857 | auto leftNumeric = GET_C(bytecode.m_lhs).jsValue().toBigIntOrInt32(globalObject); |
858 | CHECK_EXCEPTION(); |
859 | auto rightNumeric = GET_C(bytecode.m_rhs).jsValue().toBigIntOrInt32(globalObject); |
860 | CHECK_EXCEPTION(); |
861 | if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) { |
862 | if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) { |
863 | JSBigInt* result = JSBigInt::bitwiseAnd(globalObject, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric)); |
864 | CHECK_EXCEPTION(); |
865 | RETURN_PROFILED(result); |
866 | } |
867 | |
868 | THROW(createTypeError(globalObject, "Invalid mix of BigInt and other type in bitwise 'and' operation." )); |
869 | } |
870 | |
871 | RETURN_PROFILED(jsNumber(WTF::get<int32_t>(leftNumeric) & WTF::get<int32_t>(rightNumeric))); |
872 | } |
873 | |
874 | SLOW_PATH_DECL(slow_path_bitor) |
875 | { |
876 | BEGIN(); |
877 | auto bytecode = pc->as<OpBitor>(); |
878 | auto leftNumeric = GET_C(bytecode.m_lhs).jsValue().toBigIntOrInt32(globalObject); |
879 | CHECK_EXCEPTION(); |
880 | auto rightNumeric = GET_C(bytecode.m_rhs).jsValue().toBigIntOrInt32(globalObject); |
881 | CHECK_EXCEPTION(); |
882 | if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) { |
883 | if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) { |
884 | JSBigInt* result = JSBigInt::bitwiseOr(globalObject, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric)); |
885 | CHECK_EXCEPTION(); |
886 | RETURN_PROFILED(result); |
887 | } |
888 | |
889 | THROW(createTypeError(globalObject, "Invalid mix of BigInt and other type in bitwise 'or' operation." )); |
890 | } |
891 | |
892 | RETURN_PROFILED(jsNumber(WTF::get<int32_t>(leftNumeric) | WTF::get<int32_t>(rightNumeric))); |
893 | } |
894 | |
895 | SLOW_PATH_DECL(slow_path_bitxor) |
896 | { |
897 | BEGIN(); |
898 | auto bytecode = pc->as<OpBitxor>(); |
899 | auto leftNumeric = GET_C(bytecode.m_lhs).jsValue().toBigIntOrInt32(globalObject); |
900 | CHECK_EXCEPTION(); |
901 | auto rightNumeric = GET_C(bytecode.m_rhs).jsValue().toBigIntOrInt32(globalObject); |
902 | CHECK_EXCEPTION(); |
903 | if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) { |
904 | if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) { |
905 | JSBigInt* result = JSBigInt::bitwiseXor(globalObject, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric)); |
906 | CHECK_EXCEPTION(); |
907 | RETURN_PROFILED(result); |
908 | } |
909 | |
910 | THROW(createTypeError(globalObject, "Invalid mix of BigInt and other type in bitwise 'xor' operation." )); |
911 | } |
912 | |
913 | RETURN_PROFILED(jsNumber(WTF::get<int32_t>(leftNumeric) ^ WTF::get<int32_t>(rightNumeric))); |
914 | } |
915 | |
916 | SLOW_PATH_DECL(slow_path_typeof) |
917 | { |
918 | BEGIN(); |
919 | auto bytecode = pc->as<OpTypeof>(); |
920 | RETURN(jsTypeStringForValue(globalObject, GET_C(bytecode.m_value).jsValue())); |
921 | } |
922 | |
923 | SLOW_PATH_DECL(slow_path_is_object_or_null) |
924 | { |
925 | BEGIN(); |
926 | auto bytecode = pc->as<OpIsObjectOrNull>(); |
927 | RETURN(jsBoolean(jsIsObjectTypeOrNull(globalObject, GET_C(bytecode.m_operand).jsValue()))); |
928 | } |
929 | |
930 | SLOW_PATH_DECL(slow_path_is_function) |
931 | { |
932 | BEGIN(); |
933 | auto bytecode = pc->as<OpIsFunction>(); |
934 | RETURN(jsBoolean(GET_C(bytecode.m_operand).jsValue().isFunction(vm))); |
935 | } |
936 | |
937 | SLOW_PATH_DECL(slow_path_in_by_val) |
938 | { |
939 | BEGIN(); |
940 | auto bytecode = pc->as<OpInByVal>(); |
941 | auto& metadata = bytecode.metadata(codeBlock); |
942 | RETURN(jsBoolean(CommonSlowPaths::opInByVal(globalObject, GET_C(bytecode.m_base).jsValue(), GET_C(bytecode.m_property).jsValue(), &metadata.m_arrayProfile))); |
943 | } |
944 | |
945 | SLOW_PATH_DECL(slow_path_in_by_id) |
946 | { |
947 | BEGIN(); |
948 | |
949 | auto bytecode = pc->as<OpInById>(); |
950 | JSValue baseValue = GET_C(bytecode.m_base).jsValue(); |
951 | if (!baseValue.isObject()) |
952 | THROW(createInvalidInParameterError(globalObject, baseValue)); |
953 | |
954 | RETURN(jsBoolean(asObject(baseValue)->hasProperty(globalObject, codeBlock->identifier(bytecode.m_property)))); |
955 | } |
956 | |
957 | SLOW_PATH_DECL(slow_path_del_by_val) |
958 | { |
959 | BEGIN(); |
960 | auto bytecode = pc->as<OpDelByVal>(); |
961 | JSValue baseValue = GET_C(bytecode.m_base).jsValue(); |
962 | JSObject* baseObject = baseValue.toObject(globalObject); |
963 | CHECK_EXCEPTION(); |
964 | |
965 | JSValue subscript = GET_C(bytecode.m_property).jsValue(); |
966 | |
967 | bool couldDelete; |
968 | |
969 | uint32_t i; |
970 | if (subscript.getUInt32(i)) |
971 | couldDelete = baseObject->methodTable(vm)->deletePropertyByIndex(baseObject, globalObject, i); |
972 | else { |
973 | CHECK_EXCEPTION(); |
974 | auto property = subscript.toPropertyKey(globalObject); |
975 | CHECK_EXCEPTION(); |
976 | couldDelete = baseObject->methodTable(vm)->deleteProperty(baseObject, globalObject, property); |
977 | } |
978 | |
979 | if (!couldDelete && codeBlock->isStrictMode()) |
980 | THROW(createTypeError(globalObject, UnableToDeletePropertyError)); |
981 | |
982 | RETURN(jsBoolean(couldDelete)); |
983 | } |
984 | |
985 | SLOW_PATH_DECL(slow_path_strcat) |
986 | { |
987 | BEGIN(); |
988 | auto bytecode = pc->as<OpStrcat>(); |
989 | RETURN(jsStringFromRegisterArray(globalObject, &GET(bytecode.m_src), bytecode.m_count)); |
990 | } |
991 | |
992 | SLOW_PATH_DECL(slow_path_to_primitive) |
993 | { |
994 | BEGIN(); |
995 | auto bytecode = pc->as<OpToPrimitive>(); |
996 | RETURN(GET_C(bytecode.m_src).jsValue().toPrimitive(globalObject)); |
997 | } |
998 | |
999 | SLOW_PATH_DECL(slow_path_enter) |
1000 | { |
1001 | BEGIN(); |
1002 | Heap::heap(codeBlock)->writeBarrier(codeBlock); |
1003 | END(); |
1004 | } |
1005 | |
1006 | SLOW_PATH_DECL(slow_path_get_enumerable_length) |
1007 | { |
1008 | BEGIN(); |
1009 | auto bytecode = pc->as<OpGetEnumerableLength>(); |
1010 | JSValue enumeratorValue = GET(bytecode.m_base).jsValue(); |
1011 | if (enumeratorValue.isUndefinedOrNull()) |
1012 | RETURN(jsNumber(0)); |
1013 | |
1014 | JSPropertyNameEnumerator* enumerator = jsCast<JSPropertyNameEnumerator*>(enumeratorValue.asCell()); |
1015 | |
1016 | RETURN(jsNumber(enumerator->indexedLength())); |
1017 | } |
1018 | |
1019 | SLOW_PATH_DECL(slow_path_has_indexed_property) |
1020 | { |
1021 | BEGIN(); |
1022 | auto bytecode = pc->as<OpHasIndexedProperty>(); |
1023 | auto& metadata = bytecode.metadata(codeBlock); |
1024 | JSObject* base = GET(bytecode.m_base).jsValue().toObject(globalObject); |
1025 | CHECK_EXCEPTION(); |
1026 | JSValue property = GET(bytecode.m_property).jsValue(); |
1027 | metadata.m_arrayProfile.observeStructure(base->structure(vm)); |
1028 | ASSERT(property.isUInt32AsAnyInt()); |
1029 | RETURN(jsBoolean(base->hasPropertyGeneric(globalObject, property.asUInt32AsAnyInt(), PropertySlot::InternalMethodType::GetOwnProperty))); |
1030 | } |
1031 | |
1032 | SLOW_PATH_DECL(slow_path_has_structure_property) |
1033 | { |
1034 | BEGIN(); |
1035 | auto bytecode = pc->as<OpHasStructureProperty>(); |
1036 | JSObject* base = GET(bytecode.m_base).jsValue().toObject(globalObject); |
1037 | CHECK_EXCEPTION(); |
1038 | JSValue property = GET(bytecode.m_property).jsValue(); |
1039 | ASSERT(property.isString()); |
1040 | JSPropertyNameEnumerator* enumerator = jsCast<JSPropertyNameEnumerator*>(GET(bytecode.m_enumerator).jsValue().asCell()); |
1041 | if (base->structure(vm)->id() == enumerator->cachedStructureID()) |
1042 | RETURN(jsBoolean(true)); |
1043 | JSString* string = asString(property); |
1044 | auto propertyName = string->toIdentifier(globalObject); |
1045 | CHECK_EXCEPTION(); |
1046 | RETURN(jsBoolean(base->hasPropertyGeneric(globalObject, propertyName, PropertySlot::InternalMethodType::GetOwnProperty))); |
1047 | } |
1048 | |
1049 | SLOW_PATH_DECL(slow_path_has_generic_property) |
1050 | { |
1051 | BEGIN(); |
1052 | auto bytecode = pc->as<OpHasGenericProperty>(); |
1053 | JSObject* base = GET(bytecode.m_base).jsValue().toObject(globalObject); |
1054 | CHECK_EXCEPTION(); |
1055 | JSValue property = GET(bytecode.m_property).jsValue(); |
1056 | ASSERT(property.isString()); |
1057 | JSString* string = asString(property); |
1058 | auto propertyName = string->toIdentifier(globalObject); |
1059 | CHECK_EXCEPTION(); |
1060 | RETURN(jsBoolean(base->hasPropertyGeneric(globalObject, propertyName, PropertySlot::InternalMethodType::GetOwnProperty))); |
1061 | } |
1062 | |
1063 | SLOW_PATH_DECL(slow_path_get_direct_pname) |
1064 | { |
1065 | BEGIN(); |
1066 | auto bytecode = pc->as<OpGetDirectPname>(); |
1067 | JSValue baseValue = GET_C(bytecode.m_base).jsValue(); |
1068 | JSValue property = GET(bytecode.m_property).jsValue(); |
1069 | ASSERT(property.isString()); |
1070 | JSString* string = asString(property); |
1071 | auto propertyName = string->toIdentifier(globalObject); |
1072 | CHECK_EXCEPTION(); |
1073 | RETURN(baseValue.get(globalObject, propertyName)); |
1074 | } |
1075 | |
1076 | SLOW_PATH_DECL(slow_path_get_property_enumerator) |
1077 | { |
1078 | BEGIN(); |
1079 | auto bytecode = pc->as<OpGetPropertyEnumerator>(); |
1080 | JSValue baseValue = GET(bytecode.m_base).jsValue(); |
1081 | if (baseValue.isUndefinedOrNull()) |
1082 | RETURN(vm.emptyPropertyNameEnumerator()); |
1083 | |
1084 | JSObject* base = baseValue.toObject(globalObject); |
1085 | CHECK_EXCEPTION(); |
1086 | |
1087 | RETURN(propertyNameEnumerator(globalObject, base)); |
1088 | } |
1089 | |
1090 | SLOW_PATH_DECL(slow_path_enumerator_structure_pname) |
1091 | { |
1092 | BEGIN(); |
1093 | auto bytecode = pc->as<OpEnumeratorStructurePname>(); |
1094 | JSPropertyNameEnumerator* enumerator = jsCast<JSPropertyNameEnumerator*>(GET(bytecode.m_enumerator).jsValue().asCell()); |
1095 | uint32_t index = GET(bytecode.m_index).jsValue().asUInt32(); |
1096 | |
1097 | JSString* propertyName = nullptr; |
1098 | if (index < enumerator->endStructurePropertyIndex()) |
1099 | propertyName = enumerator->propertyNameAtIndex(index); |
1100 | RETURN(propertyName ? propertyName : jsNull()); |
1101 | } |
1102 | |
1103 | SLOW_PATH_DECL(slow_path_enumerator_generic_pname) |
1104 | { |
1105 | BEGIN(); |
1106 | auto bytecode = pc->as<OpEnumeratorGenericPname>(); |
1107 | JSPropertyNameEnumerator* enumerator = jsCast<JSPropertyNameEnumerator*>(GET(bytecode.m_enumerator).jsValue().asCell()); |
1108 | uint32_t index = GET(bytecode.m_index).jsValue().asUInt32(); |
1109 | |
1110 | JSString* propertyName = nullptr; |
1111 | if (enumerator->endStructurePropertyIndex() <= index && index < enumerator->endGenericPropertyIndex()) |
1112 | propertyName = enumerator->propertyNameAtIndex(index); |
1113 | RETURN(propertyName ? propertyName : jsNull()); |
1114 | } |
1115 | |
1116 | SLOW_PATH_DECL(slow_path_to_index_string) |
1117 | { |
1118 | BEGIN(); |
1119 | auto bytecode = pc->as<OpToIndexString>(); |
1120 | JSValue indexValue = GET(bytecode.m_index).jsValue(); |
1121 | ASSERT(indexValue.isUInt32AsAnyInt()); |
1122 | RETURN(jsString(vm, Identifier::from(vm, indexValue.asUInt32AsAnyInt()).string())); |
1123 | } |
1124 | |
1125 | SLOW_PATH_DECL(slow_path_profile_type_clear_log) |
1126 | { |
1127 | BEGIN(); |
1128 | vm.typeProfilerLog()->processLogEntries(vm, "LLInt log full."_s ); |
1129 | END(); |
1130 | } |
1131 | |
1132 | SLOW_PATH_DECL(slow_path_unreachable) |
1133 | { |
1134 | BEGIN(); |
1135 | UNREACHABLE_FOR_PLATFORM(); |
1136 | END(); |
1137 | } |
1138 | |
1139 | SLOW_PATH_DECL(slow_path_create_lexical_environment) |
1140 | { |
1141 | BEGIN(); |
1142 | auto bytecode = pc->as<OpCreateLexicalEnvironment>(); |
1143 | int scopeReg = bytecode.m_scope.offset(); |
1144 | JSScope* currentScope = callFrame->uncheckedR(scopeReg).Register::scope(); |
1145 | SymbolTable* symbolTable = jsCast<SymbolTable*>(GET_C(bytecode.m_symbolTable).jsValue()); |
1146 | JSValue initialValue = GET_C(bytecode.m_initialValue).jsValue(); |
1147 | ASSERT(initialValue == jsUndefined() || initialValue == jsTDZValue()); |
1148 | JSScope* newScope = JSLexicalEnvironment::create(vm, globalObject, currentScope, symbolTable, initialValue); |
1149 | RETURN(newScope); |
1150 | } |
1151 | |
1152 | SLOW_PATH_DECL(slow_path_push_with_scope) |
1153 | { |
1154 | BEGIN(); |
1155 | auto bytecode = pc->as<OpPushWithScope>(); |
1156 | JSObject* newScope = GET_C(bytecode.m_newScope).jsValue().toObject(globalObject); |
1157 | CHECK_EXCEPTION(); |
1158 | |
1159 | int scopeReg = bytecode.m_currentScope.offset(); |
1160 | JSScope* currentScope = callFrame->uncheckedR(scopeReg).Register::scope(); |
1161 | RETURN(JSWithScope::create(vm, globalObject, currentScope, newScope)); |
1162 | } |
1163 | |
1164 | SLOW_PATH_DECL(slow_path_resolve_scope_for_hoisting_func_decl_in_eval) |
1165 | { |
1166 | BEGIN(); |
1167 | auto bytecode = pc->as<OpResolveScopeForHoistingFuncDeclInEval>(); |
1168 | const Identifier& ident = codeBlock->identifier(bytecode.m_property); |
1169 | JSScope* scope = callFrame->uncheckedR(bytecode.m_scope.offset()).Register::scope(); |
1170 | JSValue resolvedScope = JSScope::resolveScopeForHoistingFuncDeclInEval(globalObject, scope, ident); |
1171 | |
1172 | CHECK_EXCEPTION(); |
1173 | |
1174 | RETURN(resolvedScope); |
1175 | } |
1176 | |
1177 | SLOW_PATH_DECL(slow_path_resolve_scope) |
1178 | { |
1179 | BEGIN(); |
1180 | auto bytecode = pc->as<OpResolveScope>(); |
1181 | auto& metadata = bytecode.metadata(codeBlock); |
1182 | const Identifier& ident = codeBlock->identifier(bytecode.m_var); |
1183 | JSScope* scope = callFrame->uncheckedR(bytecode.m_scope.offset()).Register::scope(); |
1184 | JSObject* resolvedScope = JSScope::resolve(globalObject, scope, ident); |
1185 | // Proxy can throw an error here, e.g. Proxy in with statement's @unscopables. |
1186 | CHECK_EXCEPTION(); |
1187 | |
1188 | ResolveType resolveType = metadata.m_resolveType; |
1189 | |
1190 | // ModuleVar does not keep the scope register value alive in DFG. |
1191 | ASSERT(resolveType != ModuleVar); |
1192 | |
1193 | switch (resolveType) { |
1194 | case GlobalProperty: |
1195 | case GlobalPropertyWithVarInjectionChecks: |
1196 | case UnresolvedProperty: |
1197 | case UnresolvedPropertyWithVarInjectionChecks: { |
1198 | if (resolvedScope->isGlobalObject()) { |
1199 | JSGlobalObject* globalObject = jsCast<JSGlobalObject*>(resolvedScope); |
1200 | bool hasProperty = globalObject->hasProperty(globalObject, ident); |
1201 | CHECK_EXCEPTION(); |
1202 | if (hasProperty) { |
1203 | ConcurrentJSLocker locker(codeBlock->m_lock); |
1204 | metadata.m_resolveType = needsVarInjectionChecks(resolveType) ? GlobalPropertyWithVarInjectionChecks : GlobalProperty; |
1205 | metadata.m_globalObject.set(vm, codeBlock, globalObject); |
1206 | metadata.m_globalLexicalBindingEpoch = globalObject->globalLexicalBindingEpoch(); |
1207 | } |
1208 | } else if (resolvedScope->isGlobalLexicalEnvironment()) { |
1209 | JSGlobalLexicalEnvironment* globalLexicalEnvironment = jsCast<JSGlobalLexicalEnvironment*>(resolvedScope); |
1210 | ConcurrentJSLocker locker(codeBlock->m_lock); |
1211 | metadata.m_resolveType = needsVarInjectionChecks(resolveType) ? GlobalLexicalVarWithVarInjectionChecks : GlobalLexicalVar; |
1212 | metadata.m_globalLexicalEnvironment.set(vm, codeBlock, globalLexicalEnvironment); |
1213 | } |
1214 | break; |
1215 | } |
1216 | default: |
1217 | break; |
1218 | } |
1219 | |
1220 | RETURN(resolvedScope); |
1221 | } |
1222 | |
1223 | SLOW_PATH_DECL(slow_path_create_rest) |
1224 | { |
1225 | BEGIN(); |
1226 | auto bytecode = pc->as<OpCreateRest>(); |
1227 | unsigned arraySize = GET_C(bytecode.m_arraySize).jsValue().asUInt32(); |
1228 | Structure* structure = globalObject->restParameterStructure(); |
1229 | unsigned numParamsToSkip = bytecode.m_numParametersToSkip; |
1230 | JSValue* argumentsToCopyRegion = callFrame->addressOfArgumentsStart() + numParamsToSkip; |
1231 | RETURN(constructArray(globalObject, structure, argumentsToCopyRegion, arraySize)); |
1232 | } |
1233 | |
1234 | SLOW_PATH_DECL(slow_path_get_by_id_with_this) |
1235 | { |
1236 | BEGIN(); |
1237 | auto bytecode = pc->as<OpGetByIdWithThis>(); |
1238 | const Identifier& ident = codeBlock->identifier(bytecode.m_property); |
1239 | JSValue baseValue = GET_C(bytecode.m_base).jsValue(); |
1240 | JSValue thisVal = GET_C(bytecode.m_thisValue).jsValue(); |
1241 | PropertySlot slot(thisVal, PropertySlot::PropertySlot::InternalMethodType::Get); |
1242 | JSValue result = baseValue.get(globalObject, ident, slot); |
1243 | RETURN_PROFILED(result); |
1244 | } |
1245 | |
1246 | SLOW_PATH_DECL(slow_path_get_by_val_with_this) |
1247 | { |
1248 | BEGIN(); |
1249 | |
1250 | auto bytecode = pc->as<OpGetByValWithThis>(); |
1251 | JSValue baseValue = GET_C(bytecode.m_base).jsValue(); |
1252 | JSValue thisValue = GET_C(bytecode.m_thisValue).jsValue(); |
1253 | JSValue subscript = GET_C(bytecode.m_property).jsValue(); |
1254 | |
1255 | if (LIKELY(baseValue.isCell() && subscript.isString())) { |
1256 | Structure& structure = *baseValue.asCell()->structure(vm); |
1257 | if (JSCell::canUseFastGetOwnProperty(structure)) { |
1258 | RefPtr<AtomStringImpl> existingAtomString = asString(subscript)->toExistingAtomString(globalObject); |
1259 | CHECK_EXCEPTION(); |
1260 | if (existingAtomString) { |
1261 | if (JSValue result = baseValue.asCell()->fastGetOwnProperty(vm, structure, existingAtomString.get())) |
1262 | RETURN_PROFILED(result); |
1263 | } |
1264 | } |
1265 | } |
1266 | |
1267 | PropertySlot slot(thisValue, PropertySlot::PropertySlot::InternalMethodType::Get); |
1268 | if (subscript.isUInt32()) { |
1269 | uint32_t i = subscript.asUInt32(); |
1270 | if (isJSString(baseValue) && asString(baseValue)->canGetIndex(i)) |
1271 | RETURN_PROFILED(asString(baseValue)->getIndex(globalObject, i)); |
1272 | |
1273 | RETURN_PROFILED(baseValue.get(globalObject, i, slot)); |
1274 | } |
1275 | |
1276 | baseValue.requireObjectCoercible(globalObject); |
1277 | CHECK_EXCEPTION(); |
1278 | auto property = subscript.toPropertyKey(globalObject); |
1279 | CHECK_EXCEPTION(); |
1280 | RETURN_PROFILED(baseValue.get(globalObject, property, slot)); |
1281 | } |
1282 | |
1283 | SLOW_PATH_DECL(slow_path_put_by_id_with_this) |
1284 | { |
1285 | BEGIN(); |
1286 | auto bytecode = pc->as<OpPutByIdWithThis>(); |
1287 | const Identifier& ident = codeBlock->identifier(bytecode.m_property); |
1288 | JSValue baseValue = GET_C(bytecode.m_base).jsValue(); |
1289 | JSValue thisVal = GET_C(bytecode.m_thisValue).jsValue(); |
1290 | JSValue putValue = GET_C(bytecode.m_value).jsValue(); |
1291 | PutPropertySlot slot(thisVal, codeBlock->isStrictMode(), codeBlock->putByIdContext()); |
1292 | baseValue.putInline(globalObject, ident, putValue, slot); |
1293 | END(); |
1294 | } |
1295 | |
1296 | SLOW_PATH_DECL(slow_path_put_by_val_with_this) |
1297 | { |
1298 | BEGIN(); |
1299 | auto bytecode = pc->as<OpPutByValWithThis>(); |
1300 | JSValue baseValue = GET_C(bytecode.m_base).jsValue(); |
1301 | JSValue thisValue = GET_C(bytecode.m_thisValue).jsValue(); |
1302 | JSValue subscript = GET_C(bytecode.m_property).jsValue(); |
1303 | JSValue value = GET_C(bytecode.m_value).jsValue(); |
1304 | |
1305 | auto property = subscript.toPropertyKey(globalObject); |
1306 | CHECK_EXCEPTION(); |
1307 | PutPropertySlot slot(thisValue, codeBlock->isStrictMode()); |
1308 | baseValue.put(globalObject, property, value, slot); |
1309 | END(); |
1310 | } |
1311 | |
1312 | SLOW_PATH_DECL(slow_path_define_data_property) |
1313 | { |
1314 | BEGIN(); |
1315 | auto bytecode = pc->as<OpDefineDataProperty>(); |
1316 | JSObject* base = asObject(GET_C(bytecode.m_base).jsValue()); |
1317 | JSValue property = GET_C(bytecode.m_property).jsValue(); |
1318 | JSValue value = GET_C(bytecode.m_value).jsValue(); |
1319 | JSValue attributes = GET_C(bytecode.m_attributes).jsValue(); |
1320 | ASSERT(attributes.isInt32()); |
1321 | |
1322 | auto propertyName = property.toPropertyKey(globalObject); |
1323 | CHECK_EXCEPTION(); |
1324 | PropertyDescriptor descriptor = toPropertyDescriptor(value, jsUndefined(), jsUndefined(), DefinePropertyAttributes(attributes.asInt32())); |
1325 | ASSERT((descriptor.attributes() & PropertyAttribute::Accessor) || (!descriptor.isAccessorDescriptor())); |
1326 | base->methodTable(vm)->defineOwnProperty(base, globalObject, propertyName, descriptor, true); |
1327 | END(); |
1328 | } |
1329 | |
1330 | SLOW_PATH_DECL(slow_path_define_accessor_property) |
1331 | { |
1332 | BEGIN(); |
1333 | auto bytecode = pc->as<OpDefineAccessorProperty>(); |
1334 | JSObject* base = asObject(GET_C(bytecode.m_base).jsValue()); |
1335 | JSValue property = GET_C(bytecode.m_property).jsValue(); |
1336 | JSValue getter = GET_C(bytecode.m_getter).jsValue(); |
1337 | JSValue setter = GET_C(bytecode.m_setter).jsValue(); |
1338 | JSValue attributes = GET_C(bytecode.m_attributes).jsValue(); |
1339 | ASSERT(attributes.isInt32()); |
1340 | |
1341 | auto propertyName = property.toPropertyKey(globalObject); |
1342 | CHECK_EXCEPTION(); |
1343 | PropertyDescriptor descriptor = toPropertyDescriptor(jsUndefined(), getter, setter, DefinePropertyAttributes(attributes.asInt32())); |
1344 | ASSERT((descriptor.attributes() & PropertyAttribute::Accessor) || (!descriptor.isAccessorDescriptor())); |
1345 | base->methodTable(vm)->defineOwnProperty(base, globalObject, propertyName, descriptor, true); |
1346 | END(); |
1347 | } |
1348 | |
1349 | SLOW_PATH_DECL(slow_path_throw_static_error) |
1350 | { |
1351 | BEGIN(); |
1352 | auto bytecode = pc->as<OpThrowStaticError>(); |
1353 | JSValue errorMessageValue = GET_C(bytecode.m_message).jsValue(); |
1354 | RELEASE_ASSERT(errorMessageValue.isString()); |
1355 | String errorMessage = asString(errorMessageValue)->value(globalObject); |
1356 | ErrorType errorType = bytecode.m_errorType; |
1357 | THROW(createError(globalObject, errorType, errorMessage)); |
1358 | } |
1359 | |
1360 | SLOW_PATH_DECL(slow_path_new_array_with_spread) |
1361 | { |
1362 | BEGIN(); |
1363 | auto bytecode = pc->as<OpNewArrayWithSpread>(); |
1364 | int numItems = bytecode.m_argc; |
1365 | ASSERT(numItems >= 0); |
1366 | const BitVector& bitVector = codeBlock->unlinkedCodeBlock()->bitVector(bytecode.m_bitVector); |
1367 | |
1368 | JSValue* values = bitwise_cast<JSValue*>(&GET(bytecode.m_argv)); |
1369 | |
1370 | Checked<unsigned, RecordOverflow> checkedArraySize = 0; |
1371 | for (int i = 0; i < numItems; i++) { |
1372 | if (bitVector.get(i)) { |
1373 | JSValue value = values[-i]; |
1374 | JSFixedArray* array = jsCast<JSFixedArray*>(value); |
1375 | checkedArraySize += array->size(); |
1376 | } else |
1377 | checkedArraySize += 1; |
1378 | } |
1379 | if (UNLIKELY(checkedArraySize.hasOverflowed())) |
1380 | THROW(createOutOfMemoryError(globalObject)); |
1381 | |
1382 | unsigned arraySize = checkedArraySize.unsafeGet(); |
1383 | if (UNLIKELY(arraySize >= MIN_ARRAY_STORAGE_CONSTRUCTION_LENGTH)) |
1384 | THROW(createOutOfMemoryError(globalObject)); |
1385 | |
1386 | Structure* structure = globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithContiguous); |
1387 | |
1388 | JSArray* result = JSArray::tryCreate(vm, structure, arraySize); |
1389 | if (UNLIKELY(!result)) |
1390 | THROW(createOutOfMemoryError(globalObject)); |
1391 | CHECK_EXCEPTION(); |
1392 | |
1393 | unsigned index = 0; |
1394 | for (int i = 0; i < numItems; i++) { |
1395 | JSValue value = values[-i]; |
1396 | if (bitVector.get(i)) { |
1397 | // We are spreading. |
1398 | JSFixedArray* array = jsCast<JSFixedArray*>(value); |
1399 | for (unsigned i = 0; i < array->size(); i++) { |
1400 | RELEASE_ASSERT(array->get(i)); |
1401 | result->putDirectIndex(globalObject, index, array->get(i)); |
1402 | CHECK_EXCEPTION(); |
1403 | ++index; |
1404 | } |
1405 | } else { |
1406 | // We are not spreading. |
1407 | result->putDirectIndex(globalObject, index, value); |
1408 | CHECK_EXCEPTION(); |
1409 | ++index; |
1410 | } |
1411 | } |
1412 | |
1413 | RETURN(result); |
1414 | } |
1415 | |
1416 | SLOW_PATH_DECL(slow_path_new_array_buffer) |
1417 | { |
1418 | BEGIN(); |
1419 | auto bytecode = pc->as<OpNewArrayBuffer>(); |
1420 | ASSERT(codeBlock->isConstantRegisterIndex(bytecode.m_immutableButterfly.offset())); |
1421 | JSImmutableButterfly* immutableButterfly = bitwise_cast<JSImmutableButterfly*>(GET_C(bytecode.m_immutableButterfly).jsValue().asCell()); |
1422 | auto& profile = bytecode.metadata(codeBlock).m_arrayAllocationProfile; |
1423 | |
1424 | IndexingType indexingMode = profile.selectIndexingType(); |
1425 | Structure* structure = globalObject->arrayStructureForIndexingTypeDuringAllocation(indexingMode); |
1426 | ASSERT(isCopyOnWrite(indexingMode)); |
1427 | ASSERT(!structure->outOfLineCapacity()); |
1428 | |
1429 | if (UNLIKELY(immutableButterfly->indexingMode() != indexingMode)) { |
1430 | auto* newButterfly = JSImmutableButterfly::create(vm, indexingMode, immutableButterfly->length()); |
1431 | for (unsigned i = 0; i < immutableButterfly->length(); ++i) |
1432 | newButterfly->setIndex(vm, i, immutableButterfly->get(i)); |
1433 | immutableButterfly = newButterfly; |
1434 | |
1435 | // FIXME: This is kinda gross and only works because we can't inline new_array_bufffer in the baseline. |
1436 | // We also cannot allocate a new butterfly from compilation threads since it's invalid to allocate cells from |
1437 | // a compilation thread. |
1438 | WTF::storeStoreFence(); |
1439 | codeBlock->constantRegister(bytecode.m_immutableButterfly.offset()).set(vm, codeBlock, immutableButterfly); |
1440 | WTF::storeStoreFence(); |
1441 | } |
1442 | |
1443 | JSArray* result = CommonSlowPaths::allocateNewArrayBuffer(vm, structure, immutableButterfly); |
1444 | ASSERT(isCopyOnWrite(result->indexingMode()) || globalObject->isHavingABadTime()); |
1445 | ArrayAllocationProfile::updateLastAllocationFor(&profile, result); |
1446 | RETURN(result); |
1447 | } |
1448 | |
1449 | SLOW_PATH_DECL(slow_path_spread) |
1450 | { |
1451 | BEGIN(); |
1452 | |
1453 | auto bytecode = pc->as<OpSpread>(); |
1454 | JSValue iterable = GET_C(bytecode.m_argument).jsValue(); |
1455 | |
1456 | if (iterable.isCell() && isJSArray(iterable.asCell())) { |
1457 | JSArray* array = jsCast<JSArray*>(iterable); |
1458 | if (array->isIteratorProtocolFastAndNonObservable()) { |
1459 | // JSFixedArray::createFromArray does not consult the prototype chain, |
1460 | // so we must be sure that not consulting the prototype chain would |
1461 | // produce the same value during iteration. |
1462 | RETURN(JSFixedArray::createFromArray(globalObject, vm, array)); |
1463 | } |
1464 | } |
1465 | |
1466 | JSArray* array; |
1467 | { |
1468 | JSFunction* iterationFunction = globalObject->iteratorProtocolFunction(); |
1469 | CallData callData; |
1470 | CallType callType = JSC::getCallData(vm, iterationFunction, callData); |
1471 | ASSERT(callType != CallType::None); |
1472 | |
1473 | MarkedArgumentBuffer arguments; |
1474 | arguments.append(iterable); |
1475 | ASSERT(!arguments.hasOverflowed()); |
1476 | JSValue arrayResult = call(globalObject, iterationFunction, callType, callData, jsNull(), arguments); |
1477 | CHECK_EXCEPTION(); |
1478 | array = jsCast<JSArray*>(arrayResult); |
1479 | } |
1480 | |
1481 | RETURN(JSFixedArray::createFromArray(globalObject, vm, array)); |
1482 | } |
1483 | |
1484 | } // namespace JSC |
1485 | |