DFGOperations.cpp 32.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
/*
 * Copyright (C) 2011 Apple Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 */

#include "config.h"
#include "DFGOperations.h"

#if ENABLE(DFG_JIT)

#include "CodeBlock.h"
32
#include "DFGOSRExit.h"
33
#include "DFGRepatch.h"
34
#include "InlineASM.h"
35 36 37 38 39
#include "Interpreter.h"
#include "JSByteArray.h"
#include "JSGlobalData.h"
#include "Operations.h"

40
#if CPU(X86_64)
41

42 43
#define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS(function, register) \
    asm( \
44 45
    ".globl " SYMBOL_STRING(function) "\n" \
    SYMBOL_STRING(function) ":" "\n" \
46
        "mov (%rsp), %" STRINGIZE(register) "\n" \
47
        "jmp " SYMBOL_STRING_RELOCATION(function##WithReturnAddress) "\n" \
48
    );
49 50
#define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_E(function)    FUNCTION_WRAPPER_WITH_RETURN_ADDRESS(function, rsi)
#define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_ECI(function)  FUNCTION_WRAPPER_WITH_RETURN_ADDRESS(function, rcx)
51
#define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJI(function)  FUNCTION_WRAPPER_WITH_RETURN_ADDRESS(function, rcx)
52 53
#define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(function) FUNCTION_WRAPPER_WITH_RETURN_ADDRESS(function, r8)

54
#elif CPU(X86)
55 56

#define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS(function, offset) \
57
    asm( \
58 59
    ".globl " SYMBOL_STRING(function) "\n" \
    SYMBOL_STRING(function) ":" "\n" \
60 61
        "mov (%esp), %eax\n" \
        "mov %eax, " STRINGIZE(offset) "(%esp)\n" \
62
        "jmp " SYMBOL_STRING_RELOCATION(function##WithReturnAddress) "\n" \
63
    );
64 65
#define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_E(function)    FUNCTION_WRAPPER_WITH_RETURN_ADDRESS(function, 8)
#define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_ECI(function)  FUNCTION_WRAPPER_WITH_RETURN_ADDRESS(function, 16)
66
#define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJI(function)  FUNCTION_WRAPPER_WITH_RETURN_ADDRESS(function, 20)
67 68
#define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(function) FUNCTION_WRAPPER_WITH_RETURN_ADDRESS(function, 24)

69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
#elif COMPILER(GCC) && CPU(ARM_THUMB2)

#define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_E(function) \
    asm ( \
    ".text" "\n" \
    ".align 2" "\n" \
    ".globl " SYMBOL_STRING(function) "\n" \
    HIDE_SYMBOL(function) "\n" \
    ".thumb" "\n" \
    ".thumb_func " THUMB_FUNC_PARAM(function) "\n" \
    SYMBOL_STRING(function) ":" "\n" \
        "cpy a2, lr" "\n" \
        "b " SYMBOL_STRING_RELOCATION(function) "WithReturnAddress" "\n" \
    );

#define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_ECI(function) \
    asm ( \
    ".text" "\n" \
    ".align 2" "\n" \
    ".globl " SYMBOL_STRING(function) "\n" \
    HIDE_SYMBOL(function) "\n" \
    ".thumb" "\n" \
    ".thumb_func " THUMB_FUNC_PARAM(function) "\n" \
    SYMBOL_STRING(function) ":" "\n" \
        "cpy a4, lr" "\n" \
        "b " SYMBOL_STRING_RELOCATION(function) "WithReturnAddress" "\n" \
    );

97 98 99 100 101 102 103 104 105 106 107 108 109
#define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJI(function) \
    asm ( \
    ".text" "\n" \
    ".align 2" "\n" \
    ".globl " SYMBOL_STRING(function) "\n" \
    HIDE_SYMBOL(function) "\n" \
    ".thumb" "\n" \
    ".thumb_func " THUMB_FUNC_PARAM(function) "\n" \
    SYMBOL_STRING(function) ":" "\n" \
        "str lr, [sp, #0]" "\n" \
        "b " SYMBOL_STRING_RELOCATION(function) "WithReturnAddress" "\n" \
    );

110 111 112 113 114 115 116 117 118 119 120 121 122
#define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(function) \
    asm ( \
    ".text" "\n" \
    ".align 2" "\n" \
    ".globl " SYMBOL_STRING(function) "\n" \
    HIDE_SYMBOL(function) "\n" \
    ".thumb" "\n" \
    ".thumb_func " THUMB_FUNC_PARAM(function) "\n" \
    SYMBOL_STRING(function) ":" "\n" \
        "str lr, [sp, #4]" "\n" \
        "b " SYMBOL_STRING_RELOCATION(function) "WithReturnAddress" "\n" \
    );

123
#endif
124 125 126 127 128 129 130 131 132

#define P_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_E(function) \
void* DFG_OPERATION function##WithReturnAddress(ExecState*, ReturnAddressPtr); \
FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_E(function)

#define J_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_ECI(function) \
EncodedJSValue DFG_OPERATION function##WithReturnAddress(ExecState*, JSCell*, Identifier*, ReturnAddressPtr); \
FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_ECI(function)

133 134 135 136
#define J_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJI(function) \
EncodedJSValue DFG_OPERATION function##WithReturnAddress(ExecState*, EncodedJSValue, Identifier*, ReturnAddressPtr); \
FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJI(function)

137 138 139
#define V_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(function) \
void DFG_OPERATION function##WithReturnAddress(ExecState*, EncodedJSValue, JSCell*, Identifier*, ReturnAddressPtr); \
FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(function)
140

141 142
namespace JSC { namespace DFG {

143
static inline void putByVal(ExecState* exec, JSValue baseValue, uint32_t index, JSValue value)
144 145 146
{
    JSGlobalData* globalData = &exec->globalData();

147
    if (isJSArray(baseValue)) {
148 149 150 151 152
        JSArray* array = asArray(baseValue);
        if (array->canSetIndex(index)) {
            array->setIndex(*globalData, index, value);
            return;
        }
153

154
        JSArray::putByIndex(array, exec, index, value);
155 156
        return;
    }
157

158
    if (isJSByteArray(baseValue) && asByteArray(baseValue)->canAccessIndex(index)) {
159 160 161 162
        JSByteArray* byteArray = asByteArray(baseValue);
        // FIXME: the JITstub used to relink this to an optimized form!
        if (value.isInt32()) {
            byteArray->setIndex(index, value.asInt32());
163 164 165
            return;
        }

ggaren@apple.com's avatar
ggaren@apple.com committed
166 167
        if (value.isNumber()) {
            byteArray->setIndex(index, value.asNumber());
168
            return;
169
        }
170 171 172 173 174 175
    }

    baseValue.put(exec, index, value);
}

template<bool strict>
176
ALWAYS_INLINE static void DFG_OPERATION operationPutByValInternal(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
177 178 179 180
{
    JSValue baseValue = JSValue::decode(encodedBase);
    JSValue property = JSValue::decode(encodedProperty);
    JSValue value = JSValue::decode(encodedValue);
181

182 183
    if (LIKELY(property.isUInt32())) {
        putByVal(exec, baseValue, property.asUInt32(), value);
184 185 186
        return;
    }

187 188 189 190 191 192 193 194 195 196 197
    if (property.isDouble()) {
        double propertyAsDouble = property.asDouble();
        uint32_t propertyAsUInt32 = static_cast<uint32_t>(propertyAsDouble);
        if (propertyAsDouble == propertyAsUInt32) {
            putByVal(exec, baseValue, propertyAsUInt32, value);
            return;
        }
    }

    JSGlobalData* globalData = &exec->globalData();

198 199 200 201 202 203 204 205 206 207
    // Don't put to an object if toString throws an exception.
    Identifier ident(exec, property.toString(exec));
    if (!globalData->exception) {
        PutPropertySlot slot(strict);
        baseValue.put(exec, ident, value, slot);
    }
}

extern "C" {

208
EncodedJSValue DFG_OPERATION operationConvertThis(ExecState* exec, EncodedJSValue encodedOp)
209
{
210
    return JSValue::encode(JSValue::decode(encodedOp).toThisObject(exec));
211 212
}

213
inline JSCell* createThis(ExecState* exec, JSCell* prototype, JSFunction* constructor)
214 215 216
{
#if !ASSERT_DISABLED
    ConstructData constructData;
217
    ASSERT(constructor->methodTable()->getConstructData(constructor, constructData) == ConstructTypeJS);
218 219 220 221 222
#endif
    
    JSGlobalData& globalData = exec->globalData();
    
    Structure* structure;
223 224
    if (prototype->isObject())
        structure = asObject(prototype)->inheritorID(globalData);
225 226 227
    else
        structure = constructor->scope()->globalObject->emptyObjectStructure();
    
228
    return constructEmptyObject(exec, structure);
229 230
}

231 232 233 234 235 236 237 238 239 240
JSCell* DFG_OPERATION operationCreateThis(ExecState* exec, JSCell* prototype)
{
    return createThis(exec, prototype, asFunction(exec->callee()));
}

JSCell* DFG_OPERATION operationCreateThisInlined(ExecState* exec, JSCell* prototype, JSCell* constructor)
{
    return createThis(exec, prototype, static_cast<JSFunction*>(constructor));
}

241
JSCell* DFG_OPERATION operationNewObject(ExecState* exec)
242
{
243
    return constructEmptyObject(exec);
244 245
}

246
EncodedJSValue DFG_OPERATION operationValueAdd(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
247 248 249 250
{
    JSValue op1 = JSValue::decode(encodedOp1);
    JSValue op2 = JSValue::decode(encodedOp2);
    
251 252 253
    return JSValue::encode(jsAdd(exec, op1, op2));
}

254
EncodedJSValue DFG_OPERATION operationValueAddNotNumber(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
255 256 257 258
{
    JSValue op1 = JSValue::decode(encodedOp1);
    JSValue op2 = JSValue::decode(encodedOp2);
    
259
    ASSERT(!op1.isNumber() || !op2.isNumber());
260 261 262 263 264 265
    
    if (op1.isString()) {
        if (op2.isString())
            return JSValue::encode(jsString(exec, asString(op1), asString(op2)));
        return JSValue::encode(jsString(exec, asString(op1), op2.toPrimitiveString(exec)));
    }
266 267 268 269

    return JSValue::encode(jsAddSlowCase(exec, op1, op2));
}

270 271 272
static inline EncodedJSValue getByVal(ExecState* exec, JSCell* base, uint32_t index)
{
    // FIXME: the JIT used to handle these in compiled code!
273
    if (isJSArray(base) && asArray(base)->canGetIndex(index))
274 275 276
        return JSValue::encode(asArray(base)->getIndex(index));

    // FIXME: the JITstub used to relink this to an optimized form!
277
    if (isJSString(base) && asString(base)->canGetIndex(index))
278 279 280
        return JSValue::encode(asString(base)->getIndex(exec, index));

    // FIXME: the JITstub used to relink this to an optimized form!
281
    if (isJSByteArray(base) && asByteArray(base)->canAccessIndex(index))
282 283 284 285 286
        return JSValue::encode(asByteArray(base)->getIndex(exec, index));

    return JSValue::encode(JSValue(base).get(exec, index));
}

287
EncodedJSValue DFG_OPERATION operationGetByVal(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty)
288 289 290 291 292 293 294 295
{
    JSValue baseValue = JSValue::decode(encodedBase);
    JSValue property = JSValue::decode(encodedProperty);

    if (LIKELY(baseValue.isCell())) {
        JSCell* base = baseValue.asCell();

        if (property.isUInt32()) {
296 297 298 299 300 301 302
            return getByVal(exec, base, property.asUInt32());
        } else if (property.isDouble()) {
            double propertyAsDouble = property.asDouble();
            uint32_t propertyAsUInt32 = static_cast<uint32_t>(propertyAsDouble);
            if (propertyAsUInt32 == propertyAsDouble)
                return getByVal(exec, base, propertyAsUInt32);
        } else if (property.isString()) {
303 304
            if (JSValue result = base->fastGetOwnProperty(exec, asString(property)->value(exec)))
                return JSValue::encode(result);
305 306 307 308 309 310 311
        }
    }

    Identifier ident(exec, property.toString(exec));
    return JSValue::encode(baseValue.get(exec, ident));
}

312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331
EncodedJSValue DFG_OPERATION operationGetByValCell(ExecState* exec, JSCell* base, EncodedJSValue encodedProperty)
{
    JSValue property = JSValue::decode(encodedProperty);

    if (property.isUInt32())
        return getByVal(exec, base, property.asUInt32());
    if (property.isDouble()) {
        double propertyAsDouble = property.asDouble();
        uint32_t propertyAsUInt32 = static_cast<uint32_t>(propertyAsDouble);
        if (propertyAsUInt32 == propertyAsDouble)
            return getByVal(exec, base, propertyAsUInt32);
    } else if (property.isString()) {
        if (JSValue result = base->fastGetOwnProperty(exec, asString(property)->value(exec)))
            return JSValue::encode(result);
    }

    Identifier ident(exec, property.toString(exec));
    return JSValue::encode(JSValue(base).get(exec, ident));
}

332
EncodedJSValue DFG_OPERATION operationGetById(ExecState* exec, EncodedJSValue base, Identifier* propertyName)
333
{
334
    JSValue baseValue = JSValue::decode(base);
335
    PropertySlot slot(baseValue);
336
    return JSValue::encode(baseValue.get(exec, *propertyName, slot));
337 338
}

339 340
J_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJI(operationGetByIdBuildList);
EncodedJSValue DFG_OPERATION operationGetByIdBuildListWithReturnAddress(ExecState* exec, EncodedJSValue base, Identifier* propertyName, ReturnAddressPtr returnAddress)
341
{
342
    JSValue baseValue = JSValue::decode(base);
343 344 345 346 347 348 349 350 351
    PropertySlot slot(baseValue);
    JSValue result = baseValue.get(exec, *propertyName, slot);

    StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress);
    dfgBuildGetByIDList(exec, baseValue, *propertyName, slot, stubInfo);

    return JSValue::encode(result);
}

352 353
J_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJI(operationGetByIdProtoBuildList);
EncodedJSValue DFG_OPERATION operationGetByIdProtoBuildListWithReturnAddress(ExecState* exec, EncodedJSValue base, Identifier* propertyName, ReturnAddressPtr returnAddress)
354
{
355
    JSValue baseValue = JSValue::decode(base);
356 357 358 359 360 361 362 363 364
    PropertySlot slot(baseValue);
    JSValue result = baseValue.get(exec, *propertyName, slot);

    StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress);
    dfgBuildGetByIDProtoList(exec, baseValue, *propertyName, slot, stubInfo);

    return JSValue::encode(result);
}

365 366
J_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJI(operationGetByIdOptimize);
EncodedJSValue DFG_OPERATION operationGetByIdOptimizeWithReturnAddress(ExecState* exec, EncodedJSValue base, Identifier* propertyName, ReturnAddressPtr returnAddress)
367
{
368
    JSValue baseValue = JSValue::decode(base);
369 370
    PropertySlot slot(baseValue);
    JSValue result = baseValue.get(exec, *propertyName, slot);
371
    
372 373 374 375 376 377 378 379 380
    StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress);
    if (stubInfo.seen)
        dfgRepatchGetByID(exec, baseValue, *propertyName, slot, stubInfo);
    else
        stubInfo.seen = true;

    return JSValue::encode(result);
}

381
void DFG_OPERATION operationPutByValStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
382 383 384 385
{
    operationPutByValInternal<true>(exec, encodedBase, encodedProperty, encodedValue);
}

386
void DFG_OPERATION operationPutByValNonStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
387 388 389 390
{
    operationPutByValInternal<false>(exec, encodedBase, encodedProperty, encodedValue);
}

391 392 393 394 395 396 397 398 399 400
void DFG_OPERATION operationPutByValCellStrict(ExecState* exec, JSCell* cell, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
{
    operationPutByValInternal<true>(exec, JSValue::encode(cell), encodedProperty, encodedValue);
}

void DFG_OPERATION operationPutByValCellNonStrict(ExecState* exec, JSCell* cell, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
{
    operationPutByValInternal<false>(exec, JSValue::encode(cell), encodedProperty, encodedValue);
}

401
void DFG_OPERATION operationPutByValBeyondArrayBounds(ExecState* exec, JSArray* array, int32_t index, EncodedJSValue encodedValue)
402 403 404
{
    // We should only get here if index is outside the existing vector.
    ASSERT(!array->canSetIndex(index));
405
    JSArray::putByIndex(array, exec, index, JSValue::decode(encodedValue));
406 407
}

408
EncodedJSValue DFG_OPERATION operationArrayPush(ExecState* exec, EncodedJSValue encodedValue, JSArray* array)
409 410 411 412 413 414 415 416 417 418
{
    array->push(exec, JSValue::decode(encodedValue));
    return JSValue::encode(jsNumber(array->length()));
}
        
EncodedJSValue DFG_OPERATION operationArrayPop(ExecState*, JSArray* array)
{
    return JSValue::encode(array->pop());
}
        
419
void DFG_OPERATION operationPutByIdStrict(ExecState* exec, EncodedJSValue encodedValue, JSCell* base, Identifier* propertyName)
420 421
{
    PutPropertySlot slot(true);
mhahnenberg@apple.com's avatar
mhahnenberg@apple.com committed
422
    base->methodTable()->put(base, exec, *propertyName, JSValue::decode(encodedValue), slot);
423 424
}

425
void DFG_OPERATION operationPutByIdNonStrict(ExecState* exec, EncodedJSValue encodedValue, JSCell* base, Identifier* propertyName)
426 427
{
    PutPropertySlot slot(false);
mhahnenberg@apple.com's avatar
mhahnenberg@apple.com committed
428
    base->methodTable()->put(base, exec, *propertyName, JSValue::decode(encodedValue), slot);
429 430
}

431
void DFG_OPERATION operationPutByIdDirectStrict(ExecState* exec, EncodedJSValue encodedValue, JSCell* base, Identifier* propertyName)
432 433
{
    PutPropertySlot slot(true);
434
    JSValue(base).putDirect(exec, *propertyName, JSValue::decode(encodedValue), slot);
435 436
}

437
void DFG_OPERATION operationPutByIdDirectNonStrict(ExecState* exec, EncodedJSValue encodedValue, JSCell* base, Identifier* propertyName)
438 439
{
    PutPropertySlot slot(false);
440
    JSValue(base).putDirect(exec, *propertyName, JSValue::decode(encodedValue), slot);
441 442
}

443
V_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(operationPutByIdStrictOptimize);
444
void DFG_OPERATION operationPutByIdStrictOptimizeWithReturnAddress(ExecState* exec, EncodedJSValue encodedValue, JSCell* base, Identifier* propertyName, ReturnAddressPtr returnAddress)
445 446
{
    JSValue value = JSValue::decode(encodedValue);
447
    JSValue baseValue(base);
448 449
    PutPropertySlot slot(true);
    
450
    baseValue.put(exec, *propertyName, value, slot);
451 452 453
    
    StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress);
    if (stubInfo.seen)
454
        dfgRepatchPutByID(exec, baseValue, *propertyName, slot, stubInfo, NotDirect);
455 456 457 458
    else
        stubInfo.seen = true;
}

459
V_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(operationPutByIdNonStrictOptimize);
460
void DFG_OPERATION operationPutByIdNonStrictOptimizeWithReturnAddress(ExecState* exec, EncodedJSValue encodedValue, JSCell* base, Identifier* propertyName, ReturnAddressPtr returnAddress)
461 462
{
    JSValue value = JSValue::decode(encodedValue);
463
    JSValue baseValue(base);
464 465
    PutPropertySlot slot(false);
    
466
    baseValue.put(exec, *propertyName, value, slot);
467 468 469
    
    StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress);
    if (stubInfo.seen)
470
        dfgRepatchPutByID(exec, baseValue, *propertyName, slot, stubInfo, NotDirect);
471 472 473 474
    else
        stubInfo.seen = true;
}

475
V_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(operationPutByIdDirectStrictOptimize);
476
void DFG_OPERATION operationPutByIdDirectStrictOptimizeWithReturnAddress(ExecState* exec, EncodedJSValue encodedValue, JSCell* base, Identifier* propertyName, ReturnAddressPtr returnAddress)
477 478
{
    JSValue value = JSValue::decode(encodedValue);
479
    JSValue baseValue(base);
480 481
    PutPropertySlot slot(true);
    
482
    baseValue.putDirect(exec, *propertyName, value, slot);
483 484 485
    
    StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress);
    if (stubInfo.seen)
486
        dfgRepatchPutByID(exec, baseValue, *propertyName, slot, stubInfo, Direct);
487 488 489 490
    else
        stubInfo.seen = true;
}

491
V_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(operationPutByIdDirectNonStrictOptimize);
492
void DFG_OPERATION operationPutByIdDirectNonStrictOptimizeWithReturnAddress(ExecState* exec, EncodedJSValue encodedValue, JSCell* base, Identifier* propertyName, ReturnAddressPtr returnAddress)
493 494
{
    JSValue value = JSValue::decode(encodedValue);
495
    JSValue baseValue(base);
496 497
    PutPropertySlot slot(false);
    
498
    baseValue.putDirect(exec, *propertyName, value, slot);
499 500 501
    
    StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress);
    if (stubInfo.seen)
502
        dfgRepatchPutByID(exec, baseValue, *propertyName, slot, stubInfo, Direct);
503 504 505 506
    else
        stubInfo.seen = true;
}

507
size_t DFG_OPERATION operationCompareLess(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
508
{
509
    return jsLess<true>(exec, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2));
510 511
}

512
size_t DFG_OPERATION operationCompareLessEq(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
513
{
514
    return jsLessEq<true>(exec, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2));
515 516
}

517
size_t DFG_OPERATION operationCompareGreater(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
518
{
519
    return jsLess<false>(exec, JSValue::decode(encodedOp2), JSValue::decode(encodedOp1));
520 521
}

522
size_t DFG_OPERATION operationCompareGreaterEq(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
523
{
524
    return jsLessEq<false>(exec, JSValue::decode(encodedOp2), JSValue::decode(encodedOp1));
525 526
}

527
size_t DFG_OPERATION operationCompareEq(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
528
{
529
    return JSValue::equalSlowCaseInline(exec, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2));
530 531
}

532
size_t DFG_OPERATION operationCompareStrictEqCell(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
533 534 535 536 537 538 539 540 541 542
{
    JSValue op1 = JSValue::decode(encodedOp1);
    JSValue op2 = JSValue::decode(encodedOp2);
    
    ASSERT(op1.isCell());
    ASSERT(op2.isCell());
    
    return JSValue::strictEqualSlowCaseInline(exec, op1, op2);
}

543
size_t DFG_OPERATION operationCompareStrictEq(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
544 545 546 547
{
    return JSValue::strictEqual(exec, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2));
}

548 549
EncodedJSValue DFG_OPERATION getHostCallReturnValue();
EncodedJSValue DFG_OPERATION getHostCallReturnValueWithExecState(ExecState*);
550

551
#if CPU(X86_64)
552
asm (
553 554
".globl " SYMBOL_STRING(getHostCallReturnValue) "\n"
SYMBOL_STRING(getHostCallReturnValue) ":" "\n"
555 556
    "mov -40(%r13), %r13\n"
    "mov %r13, %rdi\n"
557
    "jmp " SYMBOL_STRING_RELOCATION(getHostCallReturnValueWithExecState) "\n"
558
);
559 560
#elif CPU(X86)
asm (
561 562
".globl " SYMBOL_STRING(getHostCallReturnValue) "\n"
SYMBOL_STRING(getHostCallReturnValue) ":" "\n"
563
    "mov -40(%edi), %edi\n"
564
    "mov %edi, 4(%esp)\n"
565
    "jmp " SYMBOL_STRING_RELOCATION(getHostCallReturnValueWithExecState) "\n"
566
);
567 568 569 570 571 572 573 574 575 576 577 578 579
#elif CPU(ARM_THUMB2)
asm (
".text" "\n"
".align 2" "\n"
".globl " SYMBOL_STRING(getHostCallReturnValue) "\n"
HIDE_SYMBOL(getHostCallReturnValue) "\n"
".thumb" "\n"
".thumb_func " THUMB_FUNC_PARAM(getHostCallReturnValue) "\n"
SYMBOL_STRING(getHostCallReturnValue) ":" "\n"
    "ldr r5, [r5, #-40]" "\n"
    "cpy r0, r5" "\n"
    "b " SYMBOL_STRING_RELOCATION(getHostCallReturnValueWithExecState) "\n"
);
580
#endif
581

582
EncodedJSValue DFG_OPERATION getHostCallReturnValueWithExecState(ExecState* exec)
583 584 585 586
{
    return JSValue::encode(exec->globalData().hostCallReturnValue);
}

587
static void* handleHostCall(ExecState* execCallee, JSValue callee, CodeSpecializationKind kind)
588 589 590
{
    ExecState* exec = execCallee->callerFrame();
    JSGlobalData* globalData = &exec->globalData();
591 592 593 594

    execCallee->setScopeChain(exec->scopeChain());
    execCallee->setCodeBlock(0);

595 596 597
    if (kind == CodeForCall) {
        CallData callData;
        CallType callType = getCallData(callee, callData);
598
    
599
        ASSERT(callType != CallTypeJS);
600
    
601 602 603 604
        if (callType == CallTypeHost) {
            globalData->hostCallReturnValue = JSValue::decode(callData.native.function(execCallee));
            if (globalData->exception)
                return 0;
605

606
            return reinterpret_cast<void*>(getHostCallReturnValue);
607
        }
608 609
    
        ASSERT(callType == CallTypeNone);
610 611 612 613 614 615 616 617 618 619 620 621 622 623 624
        exec->globalData().exception = createNotAFunctionError(exec, callee);
        return 0;
    }

    ASSERT(kind == CodeForConstruct);
    
    ConstructData constructData;
    ConstructType constructType = getConstructData(callee, constructData);
    
    ASSERT(constructType != ConstructTypeJS);
    
    if (constructType == ConstructTypeHost) {
        globalData->hostCallReturnValue = JSValue::decode(constructData.native.function(execCallee));
        if (globalData->exception)
            return 0;
625

626
        return reinterpret_cast<void*>(getHostCallReturnValue);
627
    }
628 629 630
    
    ASSERT(constructType == ConstructTypeNone);
    exec->globalData().exception = createNotAConstructorError(exec, callee);
631 632 633
    return 0;
}

634
inline void* linkFor(ExecState* execCallee, ReturnAddressPtr returnAddress, CodeSpecializationKind kind)
635 636 637 638
{
    ExecState* exec = execCallee->callerFrame();
    JSGlobalData* globalData = &exec->globalData();
    JSValue calleeAsValue = execCallee->calleeAsValue();
639
    JSCell* calleeAsFunctionCell = getJSFunction(calleeAsValue);
640
    if (!calleeAsFunctionCell)
641
        return handleHostCall(execCallee, calleeAsValue, kind);
642

643
    JSFunction* callee = asFunction(calleeAsFunctionCell);
644
    execCallee->setScopeChain(callee->scopeUnchecked());
645
    ExecutableBase* executable = callee->executable();
646

647 648 649
    MacroAssemblerCodePtr codePtr;
    CodeBlock* codeBlock = 0;
    if (executable->isHostFunction())
650
        codePtr = executable->generatedJITCodeFor(kind).addressForCall();
651 652
    else {
        FunctionExecutable* functionExecutable = static_cast<FunctionExecutable*>(executable);
653
        JSObject* error = functionExecutable->compileFor(execCallee, callee->scope(), kind);
654 655 656 657
        if (error) {
            globalData->exception = createStackOverflowError(exec);
            return 0;
        }
658
        codeBlock = &functionExecutable->generatedBytecodeFor(kind);
659
        if (execCallee->argumentCountIncludingThis() < static_cast<size_t>(codeBlock->m_numParameters))
660
            codePtr = functionExecutable->generatedJITCodeWithArityCheckFor(kind);
661 662
        else
            codePtr = functionExecutable->generatedJITCodeFor(kind).addressForCall();
663 664 665 666 667
    }
    CallLinkInfo& callLinkInfo = exec->codeBlock()->getCallLinkInfo(returnAddress);
    if (!callLinkInfo.seenOnce())
        callLinkInfo.setSeen();
    else
668
        dfgLinkFor(execCallee, callLinkInfo, codeBlock, callee, codePtr, kind);
669 670 671
    return codePtr.executableAddress();
}

672
P_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_E(operationLinkCall);
673
void* DFG_OPERATION operationLinkCallWithReturnAddress(ExecState* execCallee, ReturnAddressPtr returnAddress)
674 675 676 677
{
    return linkFor(execCallee, returnAddress, CodeForCall);
}

678
P_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_E(operationLinkConstruct);
679
void* DFG_OPERATION operationLinkConstructWithReturnAddress(ExecState* execCallee, ReturnAddressPtr returnAddress)
680 681 682 683 684
{
    return linkFor(execCallee, returnAddress, CodeForConstruct);
}

inline void* virtualFor(ExecState* execCallee, CodeSpecializationKind kind)
685 686 687
{
    ExecState* exec = execCallee->callerFrame();
    JSValue calleeAsValue = execCallee->calleeAsValue();
688
    JSCell* calleeAsFunctionCell = getJSFunction(calleeAsValue);
689
    if (UNLIKELY(!calleeAsFunctionCell))
690
        return handleHostCall(execCallee, calleeAsValue, kind);
691 692
    
    JSFunction* function = asFunction(calleeAsFunctionCell);
693
    execCallee->setScopeChain(function->scopeUnchecked());
694
    ExecutableBase* executable = function->executable();
695
    if (UNLIKELY(!executable->hasJITCodeFor(kind))) {
696
        FunctionExecutable* functionExecutable = static_cast<FunctionExecutable*>(executable);
697
        JSObject* error = functionExecutable->compileFor(execCallee, function->scope(), kind);
698 699 700 701
        if (error) {
            exec->globalData().exception = error;
            return 0;
        }
702
    }
703 704 705
    return executable->generatedJITCodeWithArityCheckFor(kind).executableAddress();
}

706
void* DFG_OPERATION operationVirtualCall(ExecState* execCallee)
707 708 709 710
{
    return virtualFor(execCallee, CodeForCall);
}

711
void* DFG_OPERATION operationVirtualConstruct(ExecState* execCallee)
712 713
{
    return virtualFor(execCallee, CodeForConstruct);
714 715
}

716
EncodedJSValue DFG_OPERATION operationResolve(ExecState* exec, Identifier* propertyName)
717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732
{
    ScopeChainNode* scopeChain = exec->scopeChain();
    ScopeChainIterator iter = scopeChain->begin();
    ScopeChainIterator end = scopeChain->end();
    ASSERT(iter != end);

    do {
        JSObject* record = iter->get();
        PropertySlot slot(record);
        if (record->getPropertySlot(exec, *propertyName, slot))
            return JSValue::encode(slot.getValue(exec, *propertyName));
    } while (++iter != end);

    return throwVMError(exec, createUndefinedVariableError(exec, *propertyName));
}

733
EncodedJSValue DFG_OPERATION operationResolveBase(ExecState* exec, Identifier* propertyName)
734 735 736 737
{
    return JSValue::encode(resolveBase(exec, *propertyName, exec->scopeChain(), false));
}

738
EncodedJSValue DFG_OPERATION operationResolveBaseStrictPut(ExecState* exec, Identifier* propertyName)
739 740 741 742 743 744 745
{
    JSValue base = resolveBase(exec, *propertyName, exec->scopeChain(), true);
    if (!base)
        throwError(exec, createErrorForInvalidGlobalAssignment(exec, propertyName->ustring()));
    return JSValue::encode(base);
}

746
EncodedJSValue DFG_OPERATION operationResolveGlobal(ExecState* exec, GlobalResolveInfo* resolveInfo, Identifier* propertyName)
747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764
{
    JSGlobalObject* globalObject = exec->lexicalGlobalObject();

    PropertySlot slot(globalObject);
    if (globalObject->getPropertySlot(exec, *propertyName, slot)) {
        JSValue result = slot.getValue(exec, *propertyName);

        if (slot.isCacheableValue() && !globalObject->structure()->isUncacheableDictionary() && slot.slotBase() == globalObject) {
            resolveInfo->structure.set(exec->globalData(), exec->codeBlock()->ownerExecutable(), globalObject->structure());
            resolveInfo->offset = slot.cachedOffset();
        }

        return JSValue::encode(result);
    }

    return throwVMError(exec, createUndefinedVariableError(exec, *propertyName));
}

765
EncodedJSValue DFG_OPERATION operationToPrimitive(ExecState* exec, EncodedJSValue value)
766 767 768 769
{
    return JSValue::encode(JSValue::decode(value).toPrimitive(exec));
}

770
EncodedJSValue DFG_OPERATION operationStrCat(ExecState* exec, void* start, size_t size)
771 772 773 774
{
    return JSValue::encode(jsString(exec, static_cast<Register*>(start), size));
}

775
EncodedJSValue DFG_OPERATION operationNewArray(ExecState* exec, void* start, size_t size)
776
{
777
    return JSValue::encode(constructArray(exec, static_cast<JSValue*>(start), size));
778 779
}

780
EncodedJSValue DFG_OPERATION operationNewArrayBuffer(ExecState* exec, size_t start, size_t size)
781
{
782
    return JSValue::encode(constructArray(exec, exec->codeBlock()->constantBuffer(start), size));
783 784
}

785
EncodedJSValue DFG_OPERATION operationNewRegexp(ExecState* exec, void* regexpPtr)
786 787 788 789 790 791 792
{
    RegExp* regexp = static_cast<RegExp*>(regexpPtr);
    if (!regexp->isValid()) {
        throwError(exec, createSyntaxError(exec, "Invalid flags supplied to RegExp constructor."));
        return JSValue::encode(jsUndefined());
    }
    
793
    return JSValue::encode(RegExpObject::create(exec->globalData(), exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->regExpStructure(), regexp));
794 795
}

796
DFGHandlerEncoded DFG_OPERATION lookupExceptionHandler(ExecState* exec, ReturnAddressPtr faultLocation)
797 798 799 800 801 802 803 804 805
{
    JSValue exceptionValue = exec->exception();
    ASSERT(exceptionValue);

    unsigned vPCIndex = exec->codeBlock()->bytecodeOffset(faultLocation);
    HandlerInfo* handler = exec->globalData().interpreter->throwException(exec, exceptionValue, vPCIndex);

    void* catchRoutine = handler ? handler->nativeCode.executableAddress() : (void*)ctiOpThrowNotCaught;
    ASSERT(catchRoutine);
806
    return dfgHandlerEncoded(exec, catchRoutine);
807 808
}

809
double DFG_OPERATION dfgConvertJSValueToNumber(ExecState* exec, EncodedJSValue value)
810 811 812 813
{
    return JSValue::decode(value).toNumber(exec);
}

814
size_t DFG_OPERATION dfgConvertJSValueToInt32(ExecState* exec, EncodedJSValue value)
815
{
816 817
    // toInt32/toUInt32 return the same value; we want the value zero extended to fill the register.
    return JSValue::decode(value).toUInt32(exec);
818 819
}

820
size_t DFG_OPERATION dfgConvertJSValueToBoolean(ExecState* exec, EncodedJSValue encodedOp)
821 822 823 824
{
    return JSValue::decode(encodedOp).toBoolean(exec);
}

825
#if DFG_ENABLE(VERBOSE_SPECULATION_FAILURE)
826
void DFG_OPERATION debugOperationPrintSpeculationFailure(ExecState*, void* debugInfoRaw)
827 828
{
    SpeculationFailureDebugInfo* debugInfo = static_cast<SpeculationFailureDebugInfo*>(debugInfoRaw);
829
    CodeBlock* codeBlock = debugInfo->codeBlock;
830
    CodeBlock* alternative = codeBlock->alternative();
831
    printf("Speculation failure in %p at @%u with executeCounter = %d, reoptimizationRetryCounter = %u, optimizationDelayCounter = %u, success/fail %u/%u\n", codeBlock, debugInfo->nodeIndex, alternative ? alternative->executeCounter() : 0, alternative ? alternative->reoptimizationRetryCounter() : 0, alternative ? alternative->optimizationDelayCounter() : 0, codeBlock->speculativeSuccessCounter(), codeBlock->speculativeFailCounter());
832 833 834
}
#endif

835
} // extern "C"
836 837 838
} } // namespace JSC::DFG

#endif