1/* 2 * Copyright (C) 2011, 2012, 2013, 2014 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#include "Arguments.h" 29#include "ArityCheckFailReturnThunks.h" 30#include "ArrayConstructor.h" 31#include "CallFrame.h" 32#include "CodeProfiling.h" 33#include "CommonSlowPathsExceptions.h" 34#include "ErrorHandlingScope.h" 35#include "GetterSetter.h" 36#include "HostCallReturnValue.h" 37#include "Interpreter.h" 38#include "JIT.h" 39#include "JITStubs.h" 40#include "JSActivation.h" 41#include "JSCJSValue.h" 42#include "JSGlobalObjectFunctions.h" 43#include "JSNameScope.h" 44#include "JSPropertyNameIterator.h" 45#include "JSString.h" 46#include "JSWithScope.h" 47#include "LLIntCommon.h" 48#include "LLIntExceptions.h" 49#include "LowLevelInterpreter.h" 50#include "ObjectConstructor.h" 51#include "JSCInlines.h" 52#include "StructureRareDataInlines.h" 53#include "VariableWatchpointSetInlines.h" 54#include <wtf/StringPrintStream.h> 55 56namespace JSC { 57 58#define BEGIN_NO_SET_PC() \ 59 VM& vm = exec->vm(); \ 60 NativeCallFrameTracer tracer(&vm, exec) 61 62#ifndef NDEBUG 63#define SET_PC_FOR_STUBS() do { \ 64 exec->codeBlock()->bytecodeOffset(pc); \ 65 exec->setCurrentVPC(pc + 1); \ 66 } while (false) 67#else 68#define SET_PC_FOR_STUBS() do { \ 69 exec->setCurrentVPC(pc + 1); \ 70 } while (false) 71#endif 72 73#define RETURN_TO_THROW(exec, pc) pc = LLInt::returnToThrow(exec) 74 75#define BEGIN() \ 76 BEGIN_NO_SET_PC(); \ 77 SET_PC_FOR_STUBS() 78 79#define OP(index) (exec->uncheckedR(pc[index].u.operand)) 80#define OP_C(index) (exec->r(pc[index].u.operand)) 81 82#define RETURN_TWO(first, second) do { \ 83 return encodeResult(first, second); \ 84 } while (false) 85 86#define END_IMPL() RETURN_TWO(pc, exec) 87 88#define THROW(exceptionToThrow) do { \ 89 vm.throwException(exec, exceptionToThrow); \ 90 RETURN_TO_THROW(exec, pc); \ 91 END_IMPL(); \ 92 } while (false) 93 94#define CHECK_EXCEPTION() do { \ 95 if (UNLIKELY(vm.exception())) { \ 96 RETURN_TO_THROW(exec, pc); \ 97 END_IMPL(); \ 98 } \ 99 } while (false) 100 101#define END() do { \ 102 CHECK_EXCEPTION(); \ 103 END_IMPL(); \ 104 } while (false) 105 106#define BRANCH(opcode, condition) do { \ 107 bool bCondition = (condition); \ 108 CHECK_EXCEPTION(); \ 109 if (bCondition) \ 110 pc += pc[OPCODE_LENGTH(opcode) - 1].u.operand; \ 111 else \ 112 pc += OPCODE_LENGTH(opcode); \ 113 END_IMPL(); \ 114 } while (false) 115 116#define RETURN(value) do { \ 117 JSValue rReturnValue = (value); \ 118 CHECK_EXCEPTION(); \ 119 OP(1) = rReturnValue; \ 120 END_IMPL(); \ 121 } while (false) 122 123#define RETURN_PROFILED(opcode, value) do { \ 124 JSValue rpPeturnValue = (value); \ 125 CHECK_EXCEPTION(); \ 126 OP(1) = rpPeturnValue; \ 127 PROFILE_VALUE(opcode, rpPeturnValue); \ 128 END_IMPL(); \ 129 } while (false) 130 131#define PROFILE_VALUE(opcode, value) do { \ 132 pc[OPCODE_LENGTH(opcode) - 1].u.profile->m_buckets[0] = \ 133 JSValue::encode(value); \ 134 } while (false) 135 136#define CALL_END_IMPL(exec, callTarget) RETURN_TWO((callTarget), (exec)) 137 138#define CALL_THROW(exec, pc, exceptionToThrow) do { \ 139 ExecState* ctExec = (exec); \ 140 Instruction* ctPC = (pc); \ 141 vm.throwException(exec, exceptionToThrow); \ 142 CALL_END_IMPL(ctExec, LLInt::callToThrow(ctExec)); \ 143 } while (false) 144 145#define CALL_CHECK_EXCEPTION(exec, pc) do { \ 146 ExecState* cceExec = (exec); \ 147 Instruction* ccePC = (pc); \ 148 if (UNLIKELY(vm.exception())) \ 149 CALL_END_IMPL(cceExec, LLInt::callToThrow(cceExec)); \ 150 } while (false) 151 152#define CALL_RETURN(exec, pc, callTarget) do { \ 153 ExecState* crExec = (exec); \ 154 Instruction* crPC = (pc); \ 155 void* crCallTarget = (callTarget); \ 156 CALL_CHECK_EXCEPTION(crExec->callerFrame(), crPC); \ 157 CALL_END_IMPL(crExec, crCallTarget); \ 158 } while (false) 159 160static CommonSlowPaths::ArityCheckData* setupArityCheckData(VM& vm, int slotsToAdd) 161{ 162 CommonSlowPaths::ArityCheckData* result = vm.arityCheckData.get(); 163 result->paddedStackSpace = slotsToAdd; 164#if ENABLE(JIT) 165 if (vm.canUseJIT()) { 166 result->thunkToCall = vm.getCTIStub(arityFixup).code().executableAddress(); 167 result->returnPC = vm.arityCheckFailReturnThunks->returnPCFor(vm, slotsToAdd * stackAlignmentRegisters()).executableAddress(); 168 } else 169#endif 170 { 171 result->thunkToCall = 0; 172 result->returnPC = 0; 173 } 174 return result; 175} 176 177SLOW_PATH_DECL(slow_path_call_arityCheck) 178{ 179 BEGIN(); 180 int slotsToAdd = CommonSlowPaths::arityCheckFor(exec, &vm.interpreter->stack(), CodeForCall); 181 if (slotsToAdd < 0) { 182 exec = exec->callerFrame(); 183 ErrorHandlingScope errorScope(exec->vm()); 184 CommonSlowPaths::interpreterThrowInCaller(exec, createStackOverflowError(exec)); 185 RETURN_TWO(bitwise_cast<void*>(static_cast<uintptr_t>(1)), exec); 186 } 187 RETURN_TWO(0, setupArityCheckData(vm, slotsToAdd)); 188} 189 190SLOW_PATH_DECL(slow_path_construct_arityCheck) 191{ 192 BEGIN(); 193 int slotsToAdd = CommonSlowPaths::arityCheckFor(exec, &vm.interpreter->stack(), CodeForConstruct); 194 if (slotsToAdd < 0) { 195 exec = exec->callerFrame(); 196 ErrorHandlingScope errorScope(exec->vm()); 197 CommonSlowPaths::interpreterThrowInCaller(exec, createStackOverflowError(exec)); 198 RETURN_TWO(bitwise_cast<void*>(static_cast<uintptr_t>(1)), exec); 199 } 200 RETURN_TWO(0, setupArityCheckData(vm, slotsToAdd)); 201} 202 203SLOW_PATH_DECL(slow_path_touch_entry) 204{ 205 BEGIN(); 206 exec->codeBlock()->symbolTable()->m_functionEnteredOnce.touch(); 207 END(); 208} 209 210SLOW_PATH_DECL(slow_path_get_callee) 211{ 212 BEGIN(); 213 JSFunction* callee = jsCast<JSFunction*>(exec->callee()); 214 pc[2].u.jsCell.set(exec->vm(), exec->codeBlock()->ownerExecutable(), callee); 215 RETURN(callee); 216} 217 218SLOW_PATH_DECL(slow_path_create_arguments) 219{ 220 BEGIN(); 221 JSValue arguments = JSValue(Arguments::create(vm, exec)); 222 CHECK_EXCEPTION(); 223 exec->uncheckedR(pc[1].u.operand) = arguments; 224 exec->uncheckedR(unmodifiedArgumentsRegister(VirtualRegister(pc[1].u.operand)).offset()) = arguments; 225 END(); 226} 227 228SLOW_PATH_DECL(slow_path_create_this) 229{ 230 BEGIN(); 231 JSFunction* constructor = jsCast<JSFunction*>(OP(2).jsValue().asCell()); 232 233#if !ASSERT_DISABLED 234 ConstructData constructData; 235 ASSERT(constructor->methodTable()->getConstructData(constructor, constructData) == ConstructTypeJS); 236#endif 237 238 size_t inlineCapacity = pc[3].u.operand; 239 Structure* structure = constructor->allocationProfile(exec, inlineCapacity)->structure(); 240 RETURN(constructEmptyObject(exec, structure)); 241} 242 243SLOW_PATH_DECL(slow_path_to_this) 244{ 245 BEGIN(); 246 JSValue v1 = OP(1).jsValue(); 247 if (v1.isCell()) 248 pc[2].u.structure.set(vm, exec->codeBlock()->ownerExecutable(), v1.asCell()->structure(vm)); 249 else 250 pc[2].u.structure.clear(); 251 RETURN(v1.toThis(exec, exec->codeBlock()->isStrictMode() ? StrictMode : NotStrictMode)); 252} 253 254SLOW_PATH_DECL(slow_path_captured_mov) 255{ 256 BEGIN(); 257 JSValue value = OP_C(2).jsValue(); 258 if (VariableWatchpointSet* set = pc[3].u.watchpointSet) 259 set->notifyWrite(vm, value); 260 RETURN(value); 261} 262 263SLOW_PATH_DECL(slow_path_new_captured_func) 264{ 265 BEGIN(); 266 CodeBlock* codeBlock = exec->codeBlock(); 267 ASSERT(codeBlock->codeType() != FunctionCode || !codeBlock->needsActivation() || exec->hasActivation()); 268 JSValue value = JSFunction::create(vm, codeBlock->functionDecl(pc[2].u.operand), exec->scope()); 269 if (VariableWatchpointSet* set = pc[3].u.watchpointSet) 270 set->notifyWrite(vm, value); 271 RETURN(value); 272} 273 274SLOW_PATH_DECL(slow_path_not) 275{ 276 BEGIN(); 277 RETURN(jsBoolean(!OP_C(2).jsValue().toBoolean(exec))); 278} 279 280SLOW_PATH_DECL(slow_path_eq) 281{ 282 BEGIN(); 283 RETURN(jsBoolean(JSValue::equal(exec, OP_C(2).jsValue(), OP_C(3).jsValue()))); 284} 285 286SLOW_PATH_DECL(slow_path_neq) 287{ 288 BEGIN(); 289 RETURN(jsBoolean(!JSValue::equal(exec, OP_C(2).jsValue(), OP_C(3).jsValue()))); 290} 291 292SLOW_PATH_DECL(slow_path_stricteq) 293{ 294 BEGIN(); 295 RETURN(jsBoolean(JSValue::strictEqual(exec, OP_C(2).jsValue(), OP_C(3).jsValue()))); 296} 297 298SLOW_PATH_DECL(slow_path_nstricteq) 299{ 300 BEGIN(); 301 RETURN(jsBoolean(!JSValue::strictEqual(exec, OP_C(2).jsValue(), OP_C(3).jsValue()))); 302} 303 304SLOW_PATH_DECL(slow_path_less) 305{ 306 BEGIN(); 307 RETURN(jsBoolean(jsLess<true>(exec, OP_C(2).jsValue(), OP_C(3).jsValue()))); 308} 309 310SLOW_PATH_DECL(slow_path_lesseq) 311{ 312 BEGIN(); 313 RETURN(jsBoolean(jsLessEq<true>(exec, OP_C(2).jsValue(), OP_C(3).jsValue()))); 314} 315 316SLOW_PATH_DECL(slow_path_greater) 317{ 318 BEGIN(); 319 RETURN(jsBoolean(jsLess<false>(exec, OP_C(3).jsValue(), OP_C(2).jsValue()))); 320} 321 322SLOW_PATH_DECL(slow_path_greatereq) 323{ 324 BEGIN(); 325 RETURN(jsBoolean(jsLessEq<false>(exec, OP_C(3).jsValue(), OP_C(2).jsValue()))); 326} 327 328SLOW_PATH_DECL(slow_path_inc) 329{ 330 BEGIN(); 331 RETURN(jsNumber(OP(1).jsValue().toNumber(exec) + 1)); 332} 333 334SLOW_PATH_DECL(slow_path_dec) 335{ 336 BEGIN(); 337 RETURN(jsNumber(OP(1).jsValue().toNumber(exec) - 1)); 338} 339 340SLOW_PATH_DECL(slow_path_to_number) 341{ 342 BEGIN(); 343 RETURN(jsNumber(OP_C(2).jsValue().toNumber(exec))); 344} 345 346SLOW_PATH_DECL(slow_path_negate) 347{ 348 BEGIN(); 349 RETURN(jsNumber(-OP_C(2).jsValue().toNumber(exec))); 350} 351 352SLOW_PATH_DECL(slow_path_add) 353{ 354 BEGIN(); 355 JSValue v1 = OP_C(2).jsValue(); 356 JSValue v2 = OP_C(3).jsValue(); 357 358 if (v1.isString() && !v2.isObject()) 359 RETURN(jsString(exec, asString(v1), v2.toString(exec))); 360 361 if (v1.isNumber() && v2.isNumber()) 362 RETURN(jsNumber(v1.asNumber() + v2.asNumber())); 363 364 RETURN(jsAddSlowCase(exec, v1, v2)); 365} 366 367// The following arithmetic and bitwise operations need to be sure to run 368// toNumber() on their operands in order. (A call to toNumber() is idempotent 369// if an exception is already set on the ExecState.) 370 371SLOW_PATH_DECL(slow_path_mul) 372{ 373 BEGIN(); 374 double a = OP_C(2).jsValue().toNumber(exec); 375 double b = OP_C(3).jsValue().toNumber(exec); 376 RETURN(jsNumber(a * b)); 377} 378 379SLOW_PATH_DECL(slow_path_sub) 380{ 381 BEGIN(); 382 double a = OP_C(2).jsValue().toNumber(exec); 383 double b = OP_C(3).jsValue().toNumber(exec); 384 RETURN(jsNumber(a - b)); 385} 386 387SLOW_PATH_DECL(slow_path_div) 388{ 389 BEGIN(); 390 double a = OP_C(2).jsValue().toNumber(exec); 391 double b = OP_C(3).jsValue().toNumber(exec); 392 RETURN(jsNumber(a / b)); 393} 394 395SLOW_PATH_DECL(slow_path_mod) 396{ 397 BEGIN(); 398 double a = OP_C(2).jsValue().toNumber(exec); 399 double b = OP_C(3).jsValue().toNumber(exec); 400 RETURN(jsNumber(fmod(a, b))); 401} 402 403SLOW_PATH_DECL(slow_path_lshift) 404{ 405 BEGIN(); 406 int32_t a = OP_C(2).jsValue().toInt32(exec); 407 uint32_t b = OP_C(3).jsValue().toUInt32(exec); 408 RETURN(jsNumber(a << (b & 31))); 409} 410 411SLOW_PATH_DECL(slow_path_rshift) 412{ 413 BEGIN(); 414 int32_t a = OP_C(2).jsValue().toInt32(exec); 415 uint32_t b = OP_C(3).jsValue().toUInt32(exec); 416 RETURN(jsNumber(a >> (b & 31))); 417} 418 419SLOW_PATH_DECL(slow_path_urshift) 420{ 421 BEGIN(); 422 uint32_t a = OP_C(2).jsValue().toUInt32(exec); 423 uint32_t b = OP_C(3).jsValue().toUInt32(exec); 424 RETURN(jsNumber(static_cast<int32_t>(a >> (b & 31)))); 425} 426 427SLOW_PATH_DECL(slow_path_unsigned) 428{ 429 BEGIN(); 430 uint32_t a = OP_C(2).jsValue().toUInt32(exec); 431 RETURN(jsNumber(a)); 432} 433 434SLOW_PATH_DECL(slow_path_bitand) 435{ 436 BEGIN(); 437 int32_t a = OP_C(2).jsValue().toInt32(exec); 438 int32_t b = OP_C(3).jsValue().toInt32(exec); 439 RETURN(jsNumber(a & b)); 440} 441 442SLOW_PATH_DECL(slow_path_bitor) 443{ 444 BEGIN(); 445 int32_t a = OP_C(2).jsValue().toInt32(exec); 446 int32_t b = OP_C(3).jsValue().toInt32(exec); 447 RETURN(jsNumber(a | b)); 448} 449 450SLOW_PATH_DECL(slow_path_bitxor) 451{ 452 BEGIN(); 453 int32_t a = OP_C(2).jsValue().toInt32(exec); 454 int32_t b = OP_C(3).jsValue().toInt32(exec); 455 RETURN(jsNumber(a ^ b)); 456} 457 458SLOW_PATH_DECL(slow_path_typeof) 459{ 460 BEGIN(); 461 RETURN(jsTypeStringForValue(exec, OP_C(2).jsValue())); 462} 463 464SLOW_PATH_DECL(slow_path_is_object) 465{ 466 BEGIN(); 467 RETURN(jsBoolean(jsIsObjectType(exec, OP_C(2).jsValue()))); 468} 469 470SLOW_PATH_DECL(slow_path_is_function) 471{ 472 BEGIN(); 473 RETURN(jsBoolean(jsIsFunctionType(OP_C(2).jsValue()))); 474} 475 476SLOW_PATH_DECL(slow_path_in) 477{ 478 BEGIN(); 479 RETURN(jsBoolean(CommonSlowPaths::opIn(exec, OP_C(2).jsValue(), OP_C(3).jsValue()))); 480} 481 482SLOW_PATH_DECL(slow_path_del_by_val) 483{ 484 BEGIN(); 485 JSValue baseValue = OP_C(2).jsValue(); 486 JSObject* baseObject = baseValue.toObject(exec); 487 488 JSValue subscript = OP_C(3).jsValue(); 489 490 bool couldDelete; 491 492 uint32_t i; 493 if (subscript.getUInt32(i)) 494 couldDelete = baseObject->methodTable()->deletePropertyByIndex(baseObject, exec, i); 495 else if (isName(subscript)) 496 couldDelete = baseObject->methodTable()->deleteProperty(baseObject, exec, jsCast<NameInstance*>(subscript.asCell())->privateName()); 497 else { 498 CHECK_EXCEPTION(); 499 Identifier property(exec, subscript.toString(exec)->value(exec)); 500 CHECK_EXCEPTION(); 501 couldDelete = baseObject->methodTable()->deleteProperty(baseObject, exec, property); 502 } 503 504 if (!couldDelete && exec->codeBlock()->isStrictMode()) 505 THROW(createTypeError(exec, "Unable to delete property.")); 506 507 RETURN(jsBoolean(couldDelete)); 508} 509 510SLOW_PATH_DECL(slow_path_strcat) 511{ 512 BEGIN(); 513 RETURN(jsStringFromRegisterArray(exec, &OP(2), pc[3].u.operand)); 514} 515 516SLOW_PATH_DECL(slow_path_to_primitive) 517{ 518 BEGIN(); 519 RETURN(OP_C(2).jsValue().toPrimitive(exec)); 520} 521 522SLOW_PATH_DECL(slow_path_enter) 523{ 524 BEGIN(); 525 ScriptExecutable* ownerExecutable = exec->codeBlock()->ownerExecutable(); 526 Heap::heap(ownerExecutable)->writeBarrier(ownerExecutable); 527 END(); 528} 529 530} // namespace JSC 531