diff options
Diffstat (limited to 'Source/JavaScriptCore/llint')
-rw-r--r-- | Source/JavaScriptCore/llint/LLIntSlowPaths.cpp | 118 | ||||
-rw-r--r-- | Source/JavaScriptCore/llint/LLIntSlowPaths.h | 7 | ||||
-rw-r--r-- | Source/JavaScriptCore/llint/LowLevelInterpreter.asm | 450 | ||||
-rw-r--r-- | Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm | 127 | ||||
-rw-r--r-- | Source/JavaScriptCore/llint/LowLevelInterpreter64.asm | 140 |
5 files changed, 520 insertions, 322 deletions
diff --git a/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp b/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp index fbf5b8598..74beae98a 100644 --- a/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp +++ b/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp @@ -119,12 +119,20 @@ namespace JSC { namespace LLInt { JSValue __rp_returnValue = (value); \ LLINT_CHECK_EXCEPTION(); \ LLINT_OP(1) = __rp_returnValue; \ - pc[OPCODE_LENGTH(opcode) - 1].u.profile->m_buckets[0] = \ - JSValue::encode(__rp_returnValue); \ + LLINT_PROFILE_VALUE(opcode, __rp_returnValue); \ LLINT_END_IMPL(); \ } while (false) + +#define LLINT_PROFILE_VALUE(opcode, value) do { \ + pc[OPCODE_LENGTH(opcode) - 1].u.profile->m_buckets[0] = \ + JSValue::encode(value); \ + } while (false) + #else // ENABLE(VALUE_PROFILER) #define LLINT_RETURN_PROFILED(opcode, value) LLINT_RETURN(value) + +#define LLINT_PROFILE_VALUE(opcode, value) do { } while (false) + #endif // ENABLE(VALUE_PROFILER) #define LLINT_CALL_END_IMPL(exec, callTarget) LLINT_RETURN_TWO((callTarget), (exec)) @@ -777,52 +785,84 @@ LLINT_SLOW_PATH_DECL(slow_path_in) LLINT_SLOW_PATH_DECL(slow_path_resolve) { LLINT_BEGIN(); - LLINT_RETURN_PROFILED(op_resolve, JSScope::resolve(exec, exec->codeBlock()->identifier(pc[2].u.operand))); -} + Identifier ident = exec->codeBlock()->identifier(pc[2].u.operand); + ResolveOperations* operations = exec->codeBlock()->resolveOperations(pc[3].u.operand); + JSValue result = JSScope::resolve(exec, ident, operations); + ASSERT(operations->size()); + ASSERT(operations == exec->codeBlock()->resolveOperations(pc[3].u.operand)); + switch (operations->data()[0].m_operation) { + case ResolveOperation::GetAndReturnGlobalProperty: + pc[0].u.opcode = LLInt::getOpcode(llint_op_resolve_global_property); + break; -LLINT_SLOW_PATH_DECL(slow_path_resolve_skip) -{ - LLINT_BEGIN(); - LLINT_RETURN_PROFILED( - op_resolve_skip, - JSScope::resolveSkip( - exec, - exec->codeBlock()->identifier(pc[2].u.operand), - pc[3].u.operand)); -} + case ResolveOperation::GetAndReturnGlobalVar: + pc[0].u.opcode = LLInt::getOpcode(llint_op_resolve_global_var); + break; -LLINT_SLOW_PATH_DECL(slow_path_resolve_global) -{ - LLINT_BEGIN(); - Identifier& ident = exec->codeBlock()->identifier(pc[2].u.operand); - LLINT_RETURN_PROFILED(op_resolve_global, JSScope::resolveGlobal(exec, ident, exec->lexicalGlobalObject(), &pc[3].u.structure, &pc[4].u.operand)); -} + case ResolveOperation::SkipTopScopeNode: + pc[0].u.opcode = LLInt::getOpcode(llint_op_resolve_scoped_var_with_top_scope_check); + break; -LLINT_SLOW_PATH_DECL(slow_path_resolve_global_dynamic) -{ - // FIXME: <rdar://problem/12185487> LLInt resolve_global_dynamic doesn't check intervening scopes for modification - LLINT_BEGIN(); - Identifier& ident = exec->codeBlock()->identifier(pc[2].u.operand); - LLINT_RETURN_PROFILED(op_resolve_global_dynamic, JSScope::resolveGlobal(exec, ident, exec->lexicalGlobalObject(), &pc[3].u.structure, &pc[4].u.operand)); + case ResolveOperation::SkipScopes: + if (operations->data()[0].m_scopesToSkip) + pc[0].u.opcode = LLInt::getOpcode(llint_op_resolve_scoped_var); + else + pc[0].u.opcode = LLInt::getOpcode(llint_op_resolve_scoped_var_on_top_scope); + break; + + default: + break; + } + LLINT_RETURN_PROFILED(op_resolve, result); } -LLINT_SLOW_PATH_DECL(slow_path_resolve_for_resolve_global_dynamic) +LLINT_SLOW_PATH_DECL(slow_path_put_to_base) { LLINT_BEGIN(); - LLINT_RETURN_PROFILED(op_resolve_global_dynamic, JSScope::resolve(exec, exec->codeBlock()->identifier(pc[2].u.operand))); + PutToBaseOperation* operation = exec->codeBlock()->putToBaseOperation(pc[4].u.operand); + JSScope::resolvePut(exec, LLINT_OP_C(1).jsValue(), exec->codeBlock()->identifier(pc[2].u.operand), LLINT_OP_C(3).jsValue(), operation); + switch (operation->m_kind) { + case PutToBaseOperation::VariablePut: + pc[0].u.opcode = LLInt::getOpcode(llint_op_put_to_base_variable); + break; + + default: + break; + } + LLINT_END(); } LLINT_SLOW_PATH_DECL(slow_path_resolve_base) { LLINT_BEGIN(); Identifier& ident = exec->codeBlock()->identifier(pc[2].u.operand); + ResolveOperations* operations = exec->codeBlock()->resolveOperations(pc[4].u.operand); + JSValue result; if (pc[3].u.operand) { - if (JSValue result = JSScope::resolveBase(exec, ident, true)) - LLINT_RETURN(result); - LLINT_THROW(globalData.exception); + result = JSScope::resolveBase(exec, ident, true, operations, exec->codeBlock()->putToBaseOperation(pc[5].u.operand)); + if (!result) + LLINT_THROW(globalData.exception); + } else + result = JSScope::resolveBase(exec, ident, false, operations, exec->codeBlock()->putToBaseOperation(pc[5].u.operand)); + ASSERT(operations->size()); + switch (operations->data()[0].m_operation) { + case ResolveOperation::ReturnGlobalObjectAsBase: + pc[0].u.opcode = LLInt::getOpcode(llint_op_resolve_base_to_global); + break; + + case ResolveOperation::SkipTopScopeNode: + pc[0].u.opcode = LLInt::getOpcode(llint_op_resolve_base_to_scope_with_top_scope_check); + break; + + case ResolveOperation::SkipScopes: + pc[0].u.opcode = LLInt::getOpcode(llint_op_resolve_base_to_scope); + break; + + default: + break; } - - LLINT_RETURN_PROFILED(op_resolve_base, JSScope::resolveBase(exec, ident, false)); + LLINT_PROFILE_VALUE(op_resolve_base, result); + LLINT_RETURN(result); } LLINT_SLOW_PATH_DECL(slow_path_ensure_property_exists) @@ -839,24 +879,26 @@ LLINT_SLOW_PATH_DECL(slow_path_ensure_property_exists) LLINT_SLOW_PATH_DECL(slow_path_resolve_with_base) { LLINT_BEGIN(); - JSValue result = JSScope::resolveWithBase(exec, exec->codeBlock()->identifier(pc[3].u.operand), &LLINT_OP(1)); + ResolveOperations* operations = exec->codeBlock()->resolveOperations(pc[4].u.operand); + JSValue result = JSScope::resolveWithBase(exec, exec->codeBlock()->identifier(pc[3].u.operand), &LLINT_OP(1), operations, exec->codeBlock()->putToBaseOperation(pc[5].u.operand)); LLINT_CHECK_EXCEPTION(); LLINT_OP(2) = result; - // FIXME: technically should have profiling, but we don't do it because the DFG won't use it. + LLINT_PROFILE_VALUE(op_resolve_with_base, result); LLINT_END(); } LLINT_SLOW_PATH_DECL(slow_path_resolve_with_this) { LLINT_BEGIN(); - JSValue result = JSScope::resolveWithThis(exec, exec->codeBlock()->identifier(pc[3].u.operand), &LLINT_OP(1)); + ResolveOperations* operations = exec->codeBlock()->resolveOperations(pc[4].u.operand); + JSValue result = JSScope::resolveWithThis(exec, exec->codeBlock()->identifier(pc[3].u.operand), &LLINT_OP(1), operations); LLINT_CHECK_EXCEPTION(); LLINT_OP(2) = result; - // FIXME: technically should have profiling, but we don't do it because the DFG won't use it. + LLINT_PROFILE_VALUE(op_resolve_with_this, result); LLINT_END(); } -LLINT_SLOW_PATH_DECL(slow_path_put_global_var_check) +LLINT_SLOW_PATH_DECL(slow_path_init_global_const_check) { LLINT_BEGIN(); CodeBlock* codeBlock = exec->codeBlock(); diff --git a/Source/JavaScriptCore/llint/LLIntSlowPaths.h b/Source/JavaScriptCore/llint/LLIntSlowPaths.h index 3d770f3c5..f78476841 100644 --- a/Source/JavaScriptCore/llint/LLIntSlowPaths.h +++ b/Source/JavaScriptCore/llint/LLIntSlowPaths.h @@ -157,15 +157,12 @@ LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_is_object); LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_is_function); LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_in); LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_resolve); -LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_resolve_skip); -LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_resolve_global); -LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_resolve_global_dynamic); -LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_resolve_for_resolve_global_dynamic); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_put_to_base); LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_resolve_base); LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_ensure_property_exists); LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_resolve_with_base); LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_resolve_with_this); -LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_put_global_var_check); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_init_global_const_check); LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_get_by_id); LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_get_arguments_length); LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_put_by_id); diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter.asm index ad509e05d..022637dbe 100644 --- a/Source/JavaScriptCore/llint/LowLevelInterpreter.asm +++ b/Source/JavaScriptCore/llint/LowLevelInterpreter.asm @@ -54,8 +54,28 @@ if JSVALUE64 const PB = t6 const tagTypeNumber = csr1 const tagMask = csr2 + + macro loadisFromInstruction(offset, dest) + loadis offset * 8[PB, PC, 8], dest + end + + macro loadpFromInstruction(offset, dest) + loadp offset * 8[PB, PC, 8], dest + end + + macro storepToInstruction(value, offset) + storep value, offset * 8[PB, PC, 8] + end + else const PC = t4 + macro loadisFromInstruction(offset, dest) + loadis offset * 4[PC], dest + end + + macro loadpFromInstruction(offset, dest) + loadp offset * 4[PC], dest + end end # Constants for reasoning about value representation. @@ -100,6 +120,29 @@ const HashFlags8BitBuffer = 64 # Copied from PropertyOffset.h const firstOutOfLineOffset = 100 +# From ResolveOperations.h +const ResolveOperationFail = 0 +const ResolveOperationSetBaseToUndefined = 1 +const ResolveOperationReturnScopeAsBase = 2 +const ResolveOperationSetBaseToScope = 3 +const ResolveOperationSetBaseToGlobal = 4 +const ResolveOperationGetAndReturnScopedVar = 5 +const ResolveOperationGetAndReturnGlobalVar = 6 +const ResolveOperationGetAndReturnGlobalVarWatchable = 7 +const ResolveOperationSkipTopScopeNode = 8 +const ResolveOperationSkipScopes = 9 +const ResolveOperationReturnGlobalObjectAsBase = 10 +const ResolveOperationGetAndReturnGlobalProperty = 11 +const ResolveOperationCheckForDynamicEntriesBeforeGlobalScope = 12 + +const PutToBaseOperationKindUninitialised = 0 +const PutToBaseOperationKindGeneric = 1 +const PutToBaseOperationKindReadonly = 2 +const PutToBaseOperationKindGlobalVariablePut = 3 +const PutToBaseOperationKindGlobalVariablePutChecked = 4 +const PutToBaseOperationKindGlobalPropertyPut = 5 +const PutToBaseOperationKindVariablePut = 6 + # Allocation constants if JSVALUE64 const JSFinalObjectSizeClassIndex = 1 @@ -196,13 +239,8 @@ macro arrayProfile(structureAndIndexingType, profile, scratch) const indexingType = structureAndIndexingType if VALUE_PROFILER storep structure, ArrayProfile::m_lastSeenStructure[profile] - loadb Structure::m_indexingType[structure], indexingType - move 1, scratch - lshifti indexingType, scratch - ori scratch, ArrayProfile::m_observedArrayModes[profile] - else - loadb Structure::m_indexingType[structure], indexingType end + loadb Structure::m_indexingType[structure], indexingType end macro checkSwitchToJIT(increment, action) @@ -499,41 +537,417 @@ _llint_op_in: callSlowPath(_llint_slow_path_in) dispatch(4) +macro getPutToBaseOperationField(scratch, scratch1, fieldOffset, fieldGetter) + loadisFromInstruction(4, scratch) + mulp sizeof PutToBaseOperation, scratch, scratch + loadp CodeBlock[cfr], scratch1 + loadp VectorBufferOffset + CodeBlock::m_putToBaseOperations[scratch1], scratch1 + fieldGetter(fieldOffset[scratch1, scratch, 1]) +end + +macro moveJSValueFromRegisterWithoutProfiling(value, destBuffer, destOffsetReg) + storep value, [destBuffer, destOffsetReg, 8] +end + + +macro moveJSValueFromRegistersWithoutProfiling(tag, payload, destBuffer, destOffsetReg) + storep tag, TagOffset[destBuffer, destOffsetReg, 8] + storep payload, PayloadOffset[destBuffer, destOffsetReg, 8] +end + +macro putToBaseVariableBody(variableOffset, scratch1, scratch2, scratch3) + loadisFromInstruction(1, scratch1) + loadp PayloadOffset[cfr, scratch1, 8], scratch1 + loadp JSVariableObject::m_registers[scratch1], scratch1 + loadisFromInstruction(3, scratch2) + if JSVALUE64 + loadConstantOrVariable(scratch2, scratch3) + moveJSValueFromRegisterWithoutProfiling(scratch3, scratch1, variableOffset) + else + loadConstantOrVariable2Reg(scratch2, scratch3, scratch2) # scratch3=tag, scratch2=payload + moveJSValueFromRegistersWithoutProfiling(scratch3, scratch2, scratch1, variableOffset) + end +end + +_llint_op_put_to_base_variable: + traceExecution() + getPutToBaseOperationField(t0, t1, PutToBaseOperation::m_offset, macro(addr) + loadis addr, t0 + end) + putToBaseVariableBody(t0, t1, t2, t3) + dispatch(5) + +_llint_op_put_to_base: + traceExecution() + getPutToBaseOperationField(t0, t1, 0, macro(addr) + leap addr, t0 + bbneq PutToBaseOperation::m_kindAsUint8[t0], PutToBaseOperationKindVariablePut, .notPutToBaseVariable + loadis PutToBaseOperation::m_offset[t0], t0 + putToBaseVariableBody(t0, t1, t2, t3) + dispatch(5) + .notPutToBaseVariable: + end) + callSlowPath(_llint_slow_path_put_to_base) + dispatch(5) + +macro getResolveOperation(resolveOperationIndex, dest, scratch) + loadisFromInstruction(resolveOperationIndex, dest) + mulp sizeof ResolveOperations, dest, dest + loadp CodeBlock[cfr], scratch + loadp VectorBufferOffset + CodeBlock::m_resolveOperations[scratch], scratch + loadp VectorBufferOffset[scratch, dest, 1], dest +end + +macro getScope(loadInitialScope, scopeCount, dest, scratch) + loadInitialScope(dest) + loadi scopeCount, scratch + + btiz scratch, .done +.loop: + loadp JSScope::m_next[dest], dest + subi 1, scratch + btinz scratch, .loop + +.done: +end + +macro moveJSValue(sourceBuffer, sourceOffsetReg, destBuffer, destOffsetReg, profileOffset, scratchRegister) + if JSVALUE64 + loadp [sourceBuffer, sourceOffsetReg, 8], scratchRegister + storep scratchRegister, [destBuffer, destOffsetReg, 8] + loadpFromInstruction(profileOffset, destOffsetReg) + valueProfile(scratchRegister, destOffsetReg) + else + loadp PayloadOffset[sourceBuffer, sourceOffsetReg, 8], scratchRegister + storep scratchRegister, PayloadOffset[destBuffer, destOffsetReg, 8] + loadp TagOffset[sourceBuffer, sourceOffsetReg, 8], sourceOffsetReg + storep sourceOffsetReg, TagOffset[destBuffer, destOffsetReg, 8] + loadpFromInstruction(profileOffset, destOffsetReg) + valueProfile(sourceOffsetReg, scratchRegister, destOffsetReg) + end +end + +macro moveJSValueFromSlot(slot, destBuffer, destOffsetReg, profileOffset, scratchRegister) + if JSVALUE64 + loadp [slot], scratchRegister + storep scratchRegister, [destBuffer, destOffsetReg, 8] + loadpFromInstruction(profileOffset, destOffsetReg) + valueProfile(scratchRegister, destOffsetReg) + else + loadp PayloadOffset[slot], scratchRegister + storep scratchRegister, PayloadOffset[destBuffer, destOffsetReg, 8] + loadp TagOffset[slot], slot + storep slot, TagOffset[destBuffer, destOffsetReg, 8] + loadpFromInstruction(profileOffset, destOffsetReg) + valueProfile(slot, scratchRegister, destOffsetReg) + end +end + +macro moveJSValueFromRegister(value, destBuffer, destOffsetReg, profileOffset) + storep value, [destBuffer, destOffsetReg, 8] + loadpFromInstruction(profileOffset, destOffsetReg) + valueProfile(value, destOffsetReg) +end + +macro moveJSValueFromRegisters(tag, payload, destBuffer, destOffsetReg, profileOffset) + storep tag, TagOffset[destBuffer, destOffsetReg, 8] + storep payload, PayloadOffset[destBuffer, destOffsetReg, 8] + loadpFromInstruction(profileOffset, destOffsetReg) + valueProfile(tag, payload, destOffsetReg) +end + +_llint_op_resolve_global_property: + traceExecution() + getResolveOperation(3, t0, t1) + loadp CodeBlock[cfr], t1 + loadp CodeBlock::m_globalObject[t1], t1 + loadp ResolveOperation::m_structure[t0], t2 + bpneq JSCell::m_structure[t1], t2, _llint_op_resolve + loadis ResolveOperation::m_offset[t0], t0 + if JSVALUE64 + loadPropertyAtVariableOffsetKnownNotInline(t0, t1, t2) + loadisFromInstruction(1, t0) + moveJSValueFromRegister(t2, cfr, t0, 4) + else + loadPropertyAtVariableOffsetKnownNotInline(t0, t1, t2, t3) + loadisFromInstruction(1, t0) + moveJSValueFromRegisters(t2, t3, cfr, t0, 4) + end + dispatch(5) + +_llint_op_resolve_global_var: + traceExecution() + getResolveOperation(3, t0, t1) + loadp ResolveOperation::m_registerAddress[t0], t0 + loadisFromInstruction(1, t1) + moveJSValueFromSlot(t0, cfr, t1, 4, t3) + dispatch(5) + +macro resolveScopedVarBody(resolveOperations) + # First ResolveOperation is to skip scope chain nodes + getScope(macro(dest) + loadp ScopeChain + PayloadOffset[cfr], dest + end, + ResolveOperation::m_scopesToSkip[resolveOperations], t1, t2) + loadp JSVariableObject::m_registers[t1], t1 # t1 now contains the activation registers + + # Second ResolveOperation tells us what offset to use + loadis ResolveOperation::m_offset + sizeof ResolveOperation[resolveOperations], t2 + loadisFromInstruction(1, t3) + moveJSValue(t1, t2, cfr, t3, 4, t0) +end + +_llint_op_resolve_scoped_var: + traceExecution() + getResolveOperation(3, t0, t1) + resolveScopedVarBody(t0) + dispatch(5) + +_llint_op_resolve_scoped_var_on_top_scope: + traceExecution() + getResolveOperation(3, t0, t1) + + # Load destination index + loadisFromInstruction(1, t3) + + # We know we want the top scope chain entry + loadp ScopeChain + PayloadOffset[cfr], t1 + loadp JSVariableObject::m_registers[t1], t1 # t1 now contains the activation registers + + # Second ResolveOperation tells us what offset to use + loadis ResolveOperation::m_offset + sizeof ResolveOperation[t0], t2 + + moveJSValue(t1, t2, cfr, t3, 4, t0) + dispatch(5) + +_llint_op_resolve_scoped_var_with_top_scope_check: + traceExecution() + getResolveOperation(3, t0, t1) + # First ResolveOperation tells us what register to check + loadis ResolveOperation::m_activationRegister[t0], t1 + + loadp PayloadOffset[cfr, t1, 8], t1 + + getScope(macro(dest) + btpz t1, .scopeChainNotCreated + loadp JSScope::m_next[t1], dest + jmp .done + .scopeChainNotCreated: + loadp ScopeChain + PayloadOffset[cfr], dest + .done: + end, + # Second ResolveOperation tells us how many more nodes to skip + ResolveOperation::m_scopesToSkip + sizeof ResolveOperation[t0], t1, t2) + loadp JSVariableObject::m_registers[t1], t1 # t1 now contains the activation registers + + # Third operation tells us what offset to use + loadis ResolveOperation::m_offset + 2 * sizeof ResolveOperation[t0], t2 + loadisFromInstruction(1, t3) + moveJSValue(t1, t2, cfr, t3, 4, t0) + dispatch(5) _llint_op_resolve: traceExecution() + getResolveOperation(3, t0, t1) + btpz t0, .noInstructions + loadis ResolveOperation::m_operation[t0], t1 + bineq t1, ResolveOperationSkipScopes, .notSkipScopes + resolveScopedVarBody(t0) + dispatch(5) +.notSkipScopes: + bineq t1, ResolveOperationGetAndReturnGlobalVar, .notGetAndReturnGlobalVar + loadp ResolveOperation::m_registerAddress[t0], t0 + loadisFromInstruction(1, t1) + moveJSValueFromSlot(t0, cfr, t1, 4, t3) + dispatch(5) +.notGetAndReturnGlobalVar: + +.noInstructions: callSlowPath(_llint_slow_path_resolve) - dispatch(4) + dispatch(5) + +_llint_op_resolve_base_to_global: + traceExecution() + loadp CodeBlock[cfr], t1 + loadp CodeBlock::m_globalObject[t1], t1 + loadisFromInstruction(1, t3) + if JSVALUE64 + moveJSValueFromRegister(t1, cfr, t3, 6) + else + move CellTag, t2 + moveJSValueFromRegisters(t2, t1, cfr, t3, 6) + end + dispatch(7) +_llint_op_resolve_base_to_global_dynamic: + jmp _llint_op_resolve_base -_llint_op_resolve_skip: +_llint_op_resolve_base_to_scope: traceExecution() - callSlowPath(_llint_slow_path_resolve_skip) - dispatch(5) + getResolveOperation(4, t0, t1) + # First ResolveOperation is to skip scope chain nodes + getScope(macro(dest) + loadp ScopeChain + PayloadOffset[cfr], dest + end, + ResolveOperation::m_scopesToSkip[t0], t1, t2) + loadisFromInstruction(1, t3) + if JSVALUE64 + moveJSValueFromRegister(t1, cfr, t3, 6) + else + move CellTag, t2 + moveJSValueFromRegisters(t2, t1, cfr, t3, 6) + end + dispatch(7) +_llint_op_resolve_base_to_scope_with_top_scope_check: + traceExecution() + getResolveOperation(4, t0, t1) + # First ResolveOperation tells us what register to check + loadis ResolveOperation::m_activationRegister[t0], t1 + + loadp PayloadOffset[cfr, t1, 8], t1 + + getScope(macro(dest) + btpz t1, .scopeChainNotCreated + loadp JSScope::m_next[t1], dest + jmp .done + .scopeChainNotCreated: + loadp ScopeChain + PayloadOffset[cfr], dest + .done: + end, + # Second ResolveOperation tells us how many more nodes to skip + ResolveOperation::m_scopesToSkip + sizeof ResolveOperation[t0], t1, t2) + + loadisFromInstruction(1, t3) + if JSVALUE64 + moveJSValueFromRegister(t1, cfr, t3, 6) + else + move CellTag, t2 + moveJSValueFromRegisters(t2, t1, cfr, t3, 6) + end + dispatch(7) _llint_op_resolve_base: traceExecution() callSlowPath(_llint_slow_path_resolve_base) - dispatch(5) - + dispatch(7) _llint_op_ensure_property_exists: traceExecution() callSlowPath(_llint_slow_path_ensure_property_exists) dispatch(3) +macro interpretResolveWithBase(opcodeLength, slowPath) + traceExecution() + getResolveOperation(4, t0, t1) + btpz t0, .slowPath + + loadp ScopeChain[cfr], t3 + # Get the base + loadis ResolveOperation::m_operation[t0], t2 + + bineq t2, ResolveOperationSkipScopes, .notSkipScopes + getScope(macro(dest) move t3, dest end, + ResolveOperation::m_scopesToSkip[t0], t1, t2) + move t1, t3 + addp sizeof ResolveOperation, t0, t0 + jmp .haveCorrectScope + + .notSkipScopes: + + bineq t2, ResolveOperationSkipTopScopeNode, .notSkipTopScopeNode + loadis ResolveOperation::m_activationRegister[t0], t1 + loadp PayloadOffset[cfr, t1, 8], t1 + + getScope(macro(dest) + btpz t1, .scopeChainNotCreated + loadp JSScope::m_next[t1], dest + jmp .done + .scopeChainNotCreated: + loadp ScopeChain + PayloadOffset[cfr], dest + .done: + end, + sizeof ResolveOperation + ResolveOperation::m_scopesToSkip[t0], t1, t2) + move t1, t3 + # We've handled two opcodes here + addp 2 * sizeof ResolveOperation, t0, t0 + + .notSkipTopScopeNode: + + .haveCorrectScope: + + # t3 now contains the correct Scope + # t0 contains a pointer to the current ResolveOperation + + loadis ResolveOperation::m_operation[t0], t2 + # t2 contains the next instruction + + loadisFromInstruction(1, t1) + # t1 now contains the index for the base register + + bineq t2, ResolveOperationSetBaseToScope, .notSetBaseToScope + storep t3, PayloadOffset[cfr, t1, 8] + if JSVALUE64 + else + storep CellTag, TagOffset[cfr, t1, 8] + end + jmp .haveSetBase + + .notSetBaseToScope: + + bineq t2, ResolveOperationSetBaseToUndefined, .notSetBaseToUndefined + if JSVALUE64 + storep ValueUndefined, PayloadOffset[cfr, t1, 8] + else + storep 0, PayloadOffset[cfr, t1, 8] + storep UndefinedTag, TagOffset[cfr, t1, 8] + end + jmp .haveSetBase + + .notSetBaseToUndefined: + bineq t2, ResolveOperationSetBaseToGlobal, .slowPath + loadp JSCell::m_structure[t3], t2 + loadp Structure::m_globalObject[t2], t2 + storep t2, PayloadOffset[cfr, t1, 8] + if JSVALUE64 + else + storep CellTag, TagOffset[cfr, t1, 8] + end + + .haveSetBase: + + # Get the value + + # Load the operation into t2 + loadis ResolveOperation::m_operation + sizeof ResolveOperation[t0], t2 + + # Load the index for the value register into t1 + loadisFromInstruction(2, t1) + + bineq t2, ResolveOperationGetAndReturnScopedVar, .notGetAndReturnScopedVar + loadp JSVariableObject::m_registers[t3], t3 # t3 now contains the activation registers + + # Second ResolveOperation tells us what offset to use + loadis ResolveOperation::m_offset + sizeof ResolveOperation[t0], t2 + moveJSValue(t3, t2, cfr, t1, opcodeLength - 1, t0) + dispatch(opcodeLength) + + .notGetAndReturnScopedVar: + bineq t2, ResolveOperationGetAndReturnGlobalProperty, .slowPath + callSlowPath(slowPath) + dispatch(opcodeLength) + +.slowPath: + callSlowPath(slowPath) + dispatch(opcodeLength) +end _llint_op_resolve_with_base: - traceExecution() - callSlowPath(_llint_slow_path_resolve_with_base) - dispatch(5) + interpretResolveWithBase(7, _llint_slow_path_resolve_with_base) _llint_op_resolve_with_this: - traceExecution() - callSlowPath(_llint_slow_path_resolve_with_this) - dispatch(5) + interpretResolveWithBase(6, _llint_slow_path_resolve_with_this) macro withInlineStorage(object, propertyStorage, continuation) diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm index f0d45eb0e..d0072d714 100644 --- a/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm +++ b/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm @@ -976,126 +976,7 @@ macro resolveGlobal(size, slow) valueProfile(t2, t3, t0) end -_llint_op_resolve_global: - traceExecution() - resolveGlobal(6, .opResolveGlobalSlow) - dispatch(6) - -.opResolveGlobalSlow: - callSlowPath(_llint_slow_path_resolve_global) - dispatch(6) - - -# Gives you the scope in t0, while allowing you to optionally perform additional checks on the -# scopes as they are traversed. scopeCheck() is called with two arguments: the register -# holding the scope, and a register that can be used for scratch. Note that this does not -# use t3, so you can hold stuff in t3 if need be. -macro getScope(deBruijinIndexOperand, scopeCheck) - loadp ScopeChain + PayloadOffset[cfr], t0 - loadi deBruijinIndexOperand, t2 - - btiz t2, .done - - loadp CodeBlock[cfr], t1 - bineq CodeBlock::m_codeType[t1], FunctionCode, .loop - btbz CodeBlock::m_needsFullScopeChain[t1], .loop - - loadi CodeBlock::m_activationRegister[t1], t1 - - # Need to conditionally skip over one scope. - bieq TagOffset[cfr, t1, 8], EmptyValueTag, .noActivation - scopeCheck(t0, t1) - loadp JSScope::m_next[t0], t0 -.noActivation: - subi 1, t2 - - btiz t2, .done -.loop: - scopeCheck(t0, t1) - loadp JSScope::m_next[t0], t0 - subi 1, t2 - btinz t2, .loop - -.done: -end - -_llint_op_resolve_global_dynamic: - traceExecution() - loadp CodeBlock[cfr], t3 - loadp CodeBlock::m_globalObject[t3], t3 - loadp JSGlobalObject::m_activationStructure[t3], t3 - getScope( - 20[PC], - macro (scope, scratch) - bpneq JSCell::m_structure[scope], t3, .opResolveGlobalDynamicSuperSlow - end) - resolveGlobal(7, .opResolveGlobalDynamicSlow) - dispatch(7) - -.opResolveGlobalDynamicSuperSlow: - callSlowPath(_llint_slow_path_resolve_for_resolve_global_dynamic) - dispatch(7) - -.opResolveGlobalDynamicSlow: - callSlowPath(_llint_slow_path_resolve_global_dynamic) - dispatch(7) - - -_llint_op_get_scoped_var: - traceExecution() - # Operands are as follows: - # 4[PC] Destination for the load. - # 8[PC] Index of register in the scope. - # 12[PC] De Bruijin index. - getScope(12[PC], macro (scope, scratch) end) - loadi 4[PC], t1 - loadi 8[PC], t2 - loadp JSVariableObject::m_registers[t0], t0 - loadi TagOffset[t0, t2, 8], t3 - loadi PayloadOffset[t0, t2, 8], t0 - storei t3, TagOffset[cfr, t1, 8] - storei t0, PayloadOffset[cfr, t1, 8] - loadi 16[PC], t1 - valueProfile(t3, t0, t1) - dispatch(5) - - -_llint_op_put_scoped_var: - traceExecution() - getScope(8[PC], macro (scope, scratch) end) - loadi 12[PC], t1 - loadConstantOrVariable(t1, t3, t2) - loadi 4[PC], t1 - writeBarrier(t3, t2) - loadp JSVariableObject::m_registers[t0], t0 - storei t3, TagOffset[t0, t1, 8] - storei t2, PayloadOffset[t0, t1, 8] - dispatch(4) - - -macro getGlobalVar(size) - traceExecution() - loadp 8[PC], t0 - loadi 4[PC], t3 - loadi TagOffset[t0], t2 - loadi PayloadOffset[t0], t1 - storei t2, TagOffset[cfr, t3, 8] - storei t1, PayloadOffset[cfr, t3, 8] - loadi (size - 1) * 4[PC], t3 - valueProfile(t2, t1, t3) - dispatch(size) -end - -_llint_op_get_global_var: - getGlobalVar(4) - - -_llint_op_get_global_var_watchable: - getGlobalVar(5) - - _llint_op_init_global_const: -_llint_op_put_global_var: traceExecution() loadi 8[PC], t1 loadi 4[PC], t0 @@ -1107,22 +988,20 @@ _llint_op_put_global_var: _llint_op_init_global_const_check: -_llint_op_put_global_var_check: traceExecution() loadp 12[PC], t2 loadi 8[PC], t1 loadi 4[PC], t0 - btbnz [t2], .opPutGlobalVarCheckSlow + btbnz [t2], .opInitGlobalConstCheckSlow loadConstantOrVariable(t1, t2, t3) writeBarrier(t2, t3) storei t2, TagOffset[t0] storei t3, PayloadOffset[t0] dispatch(5) -.opPutGlobalVarCheckSlow: - callSlowPath(_llint_slow_path_put_global_var_check) +.opInitGlobalConstCheckSlow: + callSlowPath(_llint_slow_path_init_global_const_check) dispatch(5) - # We only do monomorphic get_by_id caching for now, and we do not modify the # opcode. We do, however, allow for the cache to change anytime if fails, since # ping-ponging is free. At best we get lucky and the get_by_id will continue diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm index 8b72674ab..59fa18ccf 100644 --- a/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm +++ b/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm @@ -815,139 +815,7 @@ macro loadPropertyAtVariableOffset(propertyOffsetAsInt, objectAndStorage, value) loadp (firstOutOfLineOffset - 2) * 8[objectAndStorage, propertyOffsetAsInt, 8], value end -macro resolveGlobal(size, slow) - # Operands are as follows: - # 8[PB, PC, 8] Destination for the load. - # 16[PB, PC, 8] Property identifier index in the code block. - # 24[PB, PC, 8] Structure pointer, initialized to 0 by bytecode generator. - # 32[PB, PC, 8] Offset in global object, initialized to 0 by bytecode generator. - loadp CodeBlock[cfr], t0 - loadp CodeBlock::m_globalObject[t0], t0 - loadp JSCell::m_structure[t0], t1 - bpneq t1, 24[PB, PC, 8], slow - loadis 32[PB, PC, 8], t1 - loadPropertyAtVariableOffsetKnownNotInline(t1, t0, t2) - loadis 8[PB, PC, 8], t0 - storep t2, [cfr, t0, 8] - loadp (size - 1) * 8[PB, PC, 8], t0 - valueProfile(t2, t0) -end - -_llint_op_resolve_global: - traceExecution() - resolveGlobal(6, .opResolveGlobalSlow) - dispatch(6) - -.opResolveGlobalSlow: - callSlowPath(_llint_slow_path_resolve_global) - dispatch(6) - - -# Gives you the scope in t0, while allowing you to optionally perform additional checks on the -# scopes as they are traversed. scopeCheck() is called with two arguments: the register -# holding the scope, and a register that can be used for scratch. Note that this does not -# use t3, so you can hold stuff in t3 if need be. -macro getScope(deBruijinIndexOperand, scopeCheck) - loadp ScopeChain[cfr], t0 - loadis deBruijinIndexOperand, t2 - - btiz t2, .done - - loadp CodeBlock[cfr], t1 - bineq CodeBlock::m_codeType[t1], FunctionCode, .loop - btbz CodeBlock::m_needsFullScopeChain[t1], .loop - - loadis CodeBlock::m_activationRegister[t1], t1 - - # Need to conditionally skip over one scope. - btpz [cfr, t1, 8], .noActivation - scopeCheck(t0, t1) - loadp JSScope::m_next[t0], t0 -.noActivation: - subi 1, t2 - - btiz t2, .done -.loop: - scopeCheck(t0, t1) - loadp JSScope::m_next[t0], t0 - subi 1, t2 - btinz t2, .loop - -.done: -end - -_llint_op_resolve_global_dynamic: - traceExecution() - loadp CodeBlock[cfr], t3 - loadp CodeBlock::m_globalObject[t3], t3 - loadp JSGlobalObject::m_activationStructure[t3], t3 - getScope( - 40[PB, PC, 8], - macro (scope, scratch) - bpneq JSCell::m_structure[scope], t3, .opResolveGlobalDynamicSuperSlow - end) - resolveGlobal(7, .opResolveGlobalDynamicSlow) - dispatch(7) - -.opResolveGlobalDynamicSuperSlow: - callSlowPath(_llint_slow_path_resolve_for_resolve_global_dynamic) - dispatch(7) - -.opResolveGlobalDynamicSlow: - callSlowPath(_llint_slow_path_resolve_global_dynamic) - dispatch(7) - - -_llint_op_get_scoped_var: - traceExecution() - # Operands are as follows: - # 8[PB, PC, 8] Destination for the load - # 16[PB, PC, 8] Index of register in the scope - # 24[PB, PC, 8] De Bruijin index. - getScope(24[PB, PC, 8], macro (scope, scratch) end) - loadis 8[PB, PC, 8], t1 - loadis 16[PB, PC, 8], t2 - loadp JSVariableObject::m_registers[t0], t0 - loadp [t0, t2, 8], t3 - storep t3, [cfr, t1, 8] - loadp 32[PB, PC, 8], t1 - valueProfile(t3, t1) - dispatch(5) - - -_llint_op_put_scoped_var: - traceExecution() - getScope(16[PB, PC, 8], macro (scope, scratch) end) - loadis 24[PB, PC, 8], t1 - loadConstantOrVariable(t1, t3) - loadis 8[PB, PC, 8], t1 - writeBarrier(t3) - loadp JSVariableObject::m_registers[t0], t0 - storep t3, [t0, t1, 8] - dispatch(4) - - -macro getGlobalVar(size) - traceExecution() - loadp 16[PB, PC, 8], t0 - loadis 8[PB, PC, 8], t3 - loadp [t0], t1 - storep t1, [cfr, t3, 8] - loadp (size - 1) * 8[PB, PC, 8], t0 - valueProfile(t1, t0) - dispatch(size) -end - -_llint_op_get_global_var: - getGlobalVar(4) - - -_llint_op_get_global_var_watchable: - getGlobalVar(5) - - _llint_op_init_global_const: -_llint_op_put_global_var: traceExecution() loadis 16[PB, PC, 8], t1 loadp 8[PB, PC, 8], t0 @@ -958,21 +826,19 @@ _llint_op_put_global_var: _llint_op_init_global_const_check: -_llint_op_put_global_var_check: traceExecution() loadp 24[PB, PC, 8], t2 loadis 16[PB, PC, 8], t1 loadp 8[PB, PC, 8], t0 - btbnz [t2], .opPutGlobalVarCheckSlow + btbnz [t2], .opInitGlobalConstCheckSlow loadConstantOrVariable(t1, t2) writeBarrier(t2) storep t2, [t0] dispatch(5) -.opPutGlobalVarCheckSlow: - callSlowPath(_llint_slow_path_put_global_var_check) +.opInitGlobalConstCheckSlow: + callSlowPath(_llint_slow_path_init_global_const_check) dispatch(5) - macro getById(getPropertyStorage) traceExecution() # We only do monomorphic get_by_id caching for now, and we do not modify the |