diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2016-05-24 08:28:08 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2016-05-24 08:28:08 +0000 |
commit | a4e969f4965059196ca948db781e52f7cfebf19e (patch) | |
tree | 6ca352808c8fdc52006a0f33f6ae3c593b23867d /Source/JavaScriptCore/runtime/CommonSlowPaths.cpp | |
parent | 41386e9cb918eed93b3f13648cbef387e371e451 (diff) | |
download | WebKitGtk-tarball-a4e969f4965059196ca948db781e52f7cfebf19e.tar.gz |
webkitgtk-2.12.3webkitgtk-2.12.3
Diffstat (limited to 'Source/JavaScriptCore/runtime/CommonSlowPaths.cpp')
-rw-r--r-- | Source/JavaScriptCore/runtime/CommonSlowPaths.cpp | 468 |
1 files changed, 374 insertions, 94 deletions
diff --git a/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp b/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp index f6a142e6d..78b43c4d3 100644 --- a/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp +++ b/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011, 2012, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2011-2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -25,32 +25,34 @@ #include "config.h" #include "CommonSlowPaths.h" - -#if ENABLE(JIT) || ENABLE(LLINT) - -#include "Arguments.h" #include "ArrayConstructor.h" #include "CallFrame.h" +#include "ClonedArguments.h" #include "CodeProfiling.h" #include "CommonSlowPathsExceptions.h" +#include "DirectArguments.h" +#include "Error.h" +#include "ErrorHandlingScope.h" +#include "ExceptionFuzz.h" +#include "GeneratorFrame.h" #include "GetterSetter.h" #include "HostCallReturnValue.h" #include "Interpreter.h" #include "JIT.h" -#include "JITStubs.h" -#include "JSActivation.h" +#include "JSCInlines.h" #include "JSCJSValue.h" #include "JSGlobalObjectFunctions.h" -#include "JSNameScope.h" -#include "JSPropertyNameIterator.h" +#include "JSLexicalEnvironment.h" +#include "JSPropertyNameEnumerator.h" #include "JSString.h" #include "JSWithScope.h" #include "LLIntCommon.h" #include "LLIntExceptions.h" #include "LowLevelInterpreter.h" #include "ObjectConstructor.h" -#include "Operations.h" +#include "ScopedArguments.h" #include "StructureRareDataInlines.h" +#include "TypeProfilerLog.h" #include <wtf/StringPrintStream.h> namespace JSC { @@ -70,11 +72,7 @@ namespace JSC { } while (false) #endif -#if ENABLE(LLINT) #define RETURN_TO_THROW(exec, pc) pc = LLInt::returnToThrow(exec) -#else -#define RETURN_TO_THROW(exec, pc) -#endif #define BEGIN() \ BEGIN_NO_SET_PC(); \ @@ -96,6 +94,7 @@ namespace JSC { } while (false) #define CHECK_EXCEPTION() do { \ + doExceptionFuzzingIfEnabled(exec, "CommonSlowPaths", pc); \ if (UNLIKELY(vm.exception())) { \ RETURN_TO_THROW(exec, pc); \ END_IMPL(); \ @@ -117,20 +116,19 @@ namespace JSC { END_IMPL(); \ } while (false) -#define RETURN(value) do { \ - JSValue rReturnValue = (value); \ - CHECK_EXCEPTION(); \ - OP(1) = rReturnValue; \ - END_IMPL(); \ +#define RETURN_WITH_PROFILING(value__, profilingAction__) do { \ + JSValue returnValue__ = (value__); \ + CHECK_EXCEPTION(); \ + OP(1) = returnValue__; \ + profilingAction__; \ + END_IMPL(); \ } while (false) -#define RETURN_PROFILED(opcode, value) do { \ - JSValue rpPeturnValue = (value); \ - CHECK_EXCEPTION(); \ - OP(1) = rpPeturnValue; \ - PROFILE_VALUE(opcode, rpPeturnValue); \ - END_IMPL(); \ - } while (false) +#define RETURN(value) \ + RETURN_WITH_PROFILING(value, { }) + +#define RETURN_PROFILED(opcode__, value__) \ + RETURN_WITH_PROFILING(value__, PROFILE_VALUE(opcode__, returnValue__)) #define PROFILE_VALUE(opcode, value) do { \ pc[OPCODE_LENGTH(opcode) - 1].u.profile->m_buckets[0] = \ @@ -161,67 +159,78 @@ namespace JSC { CALL_END_IMPL(crExec, crCallTarget); \ } while (false) +static CommonSlowPaths::ArityCheckData* setupArityCheckData(VM& vm, int slotsToAdd) +{ + CommonSlowPaths::ArityCheckData* result = vm.arityCheckData.get(); + result->paddedStackSpace = slotsToAdd; +#if ENABLE(JIT) + if (vm.canUseJIT()) + result->thunkToCall = vm.getCTIStub(arityFixupGenerator).code().executableAddress(); + else +#endif + result->thunkToCall = 0; + return result; +} + SLOW_PATH_DECL(slow_path_call_arityCheck) { BEGIN(); - int SlotsToAdd = CommonSlowPaths::arityCheckFor(exec, &vm.interpreter->stack(), CodeForCall); - if (SlotsToAdd < 0) { + int slotsToAdd = CommonSlowPaths::arityCheckFor(exec, &vm.interpreter->stack(), CodeForCall); + if (slotsToAdd < 0) { exec = exec->callerFrame(); + ErrorHandlingScope errorScope(exec->vm()); CommonSlowPaths::interpreterThrowInCaller(exec, createStackOverflowError(exec)); RETURN_TWO(bitwise_cast<void*>(static_cast<uintptr_t>(1)), exec); } - RETURN_TWO(0, reinterpret_cast<ExecState*>(SlotsToAdd)); + RETURN_TWO(0, setupArityCheckData(vm, slotsToAdd)); } SLOW_PATH_DECL(slow_path_construct_arityCheck) { BEGIN(); - int SlotsToAdd = CommonSlowPaths::arityCheckFor(exec, &vm.interpreter->stack(), CodeForConstruct); - if (SlotsToAdd < 0) { + int slotsToAdd = CommonSlowPaths::arityCheckFor(exec, &vm.interpreter->stack(), CodeForConstruct); + if (slotsToAdd < 0) { exec = exec->callerFrame(); + ErrorHandlingScope errorScope(exec->vm()); CommonSlowPaths::interpreterThrowInCaller(exec, createStackOverflowError(exec)); RETURN_TWO(bitwise_cast<void*>(static_cast<uintptr_t>(1)), exec); } - RETURN_TWO(0, reinterpret_cast<ExecState*>(SlotsToAdd)); + RETURN_TWO(0, setupArityCheckData(vm, slotsToAdd)); } -SLOW_PATH_DECL(slow_path_touch_entry) +SLOW_PATH_DECL(slow_path_create_direct_arguments) { BEGIN(); - exec->codeBlock()->symbolTable()->m_functionEnteredOnce.touch(); - END(); + RETURN(DirectArguments::createByCopying(exec)); } -SLOW_PATH_DECL(slow_path_get_callee) +SLOW_PATH_DECL(slow_path_create_scoped_arguments) { BEGIN(); - JSFunction* callee = jsCast<JSFunction*>(exec->callee()); - pc[2].u.jsCell.set(exec->vm(), exec->codeBlock()->ownerExecutable(), callee); - RETURN(callee); + JSLexicalEnvironment* scope = jsCast<JSLexicalEnvironment*>(OP(2).jsValue()); + ScopedArgumentsTable* table = scope->symbolTable()->arguments(); + RETURN(ScopedArguments::createByCopying(exec, table, scope)); } -SLOW_PATH_DECL(slow_path_create_arguments) +SLOW_PATH_DECL(slow_path_create_out_of_band_arguments) { BEGIN(); - JSValue arguments = JSValue(Arguments::create(vm, exec)); - CHECK_EXCEPTION(); - exec->uncheckedR(pc[1].u.operand) = arguments; - exec->uncheckedR(unmodifiedArgumentsRegister(VirtualRegister(pc[1].u.operand)).offset()) = arguments; - END(); + RETURN(ClonedArguments::createWithMachineFrame(exec, exec, ArgumentsMode::Cloned)); } SLOW_PATH_DECL(slow_path_create_this) { BEGIN(); JSFunction* constructor = jsCast<JSFunction*>(OP(2).jsValue().asCell()); - -#if !ASSERT_DISABLED - ConstructData constructData; - ASSERT(constructor->methodTable()->getConstructData(constructor, constructData) == ConstructTypeJS); -#endif + + auto& cacheWriteBarrier = pc[4].u.jsCell; + if (!cacheWriteBarrier) + cacheWriteBarrier.set(exec->vm(), exec->codeBlock(), constructor); + else if (cacheWriteBarrier.unvalidatedGet() != JSCell::seenMultipleCalleeObjects() && cacheWriteBarrier.get() != constructor) + cacheWriteBarrier.setWithoutWriteBarrier(JSCell::seenMultipleCalleeObjects()); size_t inlineCapacity = pc[3].u.operand; - Structure* structure = constructor->allocationProfile(exec, inlineCapacity)->structure(); + Structure* structure = constructor->rareData(exec, inlineCapacity)->objectAllocationProfile()->structure(); RETURN(constructEmptyObject(exec, structure)); } @@ -229,34 +238,31 @@ SLOW_PATH_DECL(slow_path_to_this) { BEGIN(); JSValue v1 = OP(1).jsValue(); - if (v1.isCell()) - pc[2].u.structure.set(exec->vm(), exec->codeBlock()->ownerExecutable(), v1.asCell()->structure()); - else + if (v1.isCell()) { + Structure* myStructure = v1.asCell()->structure(vm); + Structure* otherStructure = pc[2].u.structure.get(); + if (myStructure != otherStructure) { + if (otherStructure) + pc[3].u.toThisStatus = ToThisConflicted; + pc[2].u.structure.set(vm, exec->codeBlock(), myStructure); + } + } else { + pc[3].u.toThisStatus = ToThisConflicted; pc[2].u.structure.clear(); + } RETURN(v1.toThis(exec, exec->codeBlock()->isStrictMode() ? StrictMode : NotStrictMode)); } -SLOW_PATH_DECL(slow_path_captured_mov) +SLOW_PATH_DECL(slow_path_throw_tdz_error) { BEGIN(); - JSValue value = OP_C(2).jsValue(); - if (VariableWatchpointSet* set = pc[3].u.watchpointSet) - set->notifyWrite(value); - RETURN(value); + THROW(createTDZError(exec)); } -SLOW_PATH_DECL(slow_path_new_captured_func) +SLOW_PATH_DECL(slow_path_throw_strict_mode_readonly_property_write_error) { BEGIN(); - CodeBlock* codeBlock = exec->codeBlock(); - ASSERT( - codeBlock->codeType() != FunctionCode - || !codeBlock->needsFullScopeChain() - || exec->uncheckedR(codeBlock->activationRegister().offset()).jsValue()); - JSValue value = JSFunction::create(vm, codeBlock->functionDecl(pc[2].u.operand), exec->scope()); - if (VariableWatchpointSet* set = pc[3].u.watchpointSet) - set->notifyWrite(value); - RETURN(value); + THROW(createTypeError(exec, ASCIILiteral(StrictModeReadonlyPropertyWriteError))); } SLOW_PATH_DECL(slow_path_not) @@ -331,25 +337,69 @@ SLOW_PATH_DECL(slow_path_to_number) RETURN(jsNumber(OP_C(2).jsValue().toNumber(exec))); } +SLOW_PATH_DECL(slow_path_to_string) +{ + BEGIN(); + RETURN(OP_C(2).jsValue().toString(exec)); +} + SLOW_PATH_DECL(slow_path_negate) { BEGIN(); RETURN(jsNumber(-OP_C(2).jsValue().toNumber(exec))); } +#if ENABLE(DFG_JIT) +static void updateResultProfileForBinaryArithOp(ExecState* exec, Instruction* pc, JSValue result, JSValue left, JSValue right) +{ + CodeBlock* codeBlock = exec->codeBlock(); + unsigned bytecodeOffset = codeBlock->bytecodeOffset(pc); + ResultProfile* profile = codeBlock->ensureResultProfile(bytecodeOffset); + + if (result.isNumber()) { + if (!result.isInt32()) { + if (left.isInt32() && right.isInt32()) + profile->setObservedInt32Overflow(); + + double doubleVal = result.asNumber(); + if (!doubleVal && std::signbit(doubleVal)) + profile->setObservedNegZeroDouble(); + else { + profile->setObservedNonNegZeroDouble(); + + // The Int52 overflow check here intentionally omits 1ll << 51 as a valid negative Int52 value. + // Therefore, we will get a false positive if the result is that value. This is intentionally + // done to simplify the checking algorithm. + static const int64_t int52OverflowPoint = (1ll << 51); + int64_t int64Val = static_cast<int64_t>(std::abs(doubleVal)); + if (int64Val >= int52OverflowPoint) + profile->setObservedInt52Overflow(); + } + } + } else + profile->setObservedNonNumber(); +} +#else +static void updateResultProfileForBinaryArithOp(ExecState*, Instruction*, JSValue, JSValue, JSValue) { } +#endif + SLOW_PATH_DECL(slow_path_add) { BEGIN(); JSValue v1 = OP_C(2).jsValue(); JSValue v2 = OP_C(3).jsValue(); - + JSValue result; + if (v1.isString() && !v2.isObject()) - RETURN(jsString(exec, asString(v1), v2.toString(exec))); - - if (v1.isNumber() && v2.isNumber()) - RETURN(jsNumber(v1.asNumber() + v2.asNumber())); - - RETURN(jsAddSlowCase(exec, v1, v2)); + result = jsString(exec, asString(v1), v2.toString(exec)); + else if (v1.isNumber() && v2.isNumber()) + result = jsNumber(v1.asNumber() + v2.asNumber()); + else + result = jsAddSlowCase(exec, v1, v2); + + RETURN_WITH_PROFILING(result, { + updateResultProfileForBinaryArithOp(exec, pc, result, v1, v2); + }); } // The following arithmetic and bitwise operations need to be sure to run @@ -359,25 +409,40 @@ SLOW_PATH_DECL(slow_path_add) SLOW_PATH_DECL(slow_path_mul) { BEGIN(); - double a = OP_C(2).jsValue().toNumber(exec); - double b = OP_C(3).jsValue().toNumber(exec); - RETURN(jsNumber(a * b)); + JSValue left = OP_C(2).jsValue(); + JSValue right = OP_C(3).jsValue(); + double a = left.toNumber(exec); + double b = right.toNumber(exec); + JSValue result = jsNumber(a * b); + RETURN_WITH_PROFILING(result, { + updateResultProfileForBinaryArithOp(exec, pc, result, left, right); + }); } SLOW_PATH_DECL(slow_path_sub) { BEGIN(); - double a = OP_C(2).jsValue().toNumber(exec); - double b = OP_C(3).jsValue().toNumber(exec); - RETURN(jsNumber(a - b)); + JSValue left = OP_C(2).jsValue(); + JSValue right = OP_C(3).jsValue(); + double a = left.toNumber(exec); + double b = right.toNumber(exec); + JSValue result = jsNumber(a - b); + RETURN_WITH_PROFILING(result, { + updateResultProfileForBinaryArithOp(exec, pc, result, left, right); + }); } SLOW_PATH_DECL(slow_path_div) { BEGIN(); - double a = OP_C(2).jsValue().toNumber(exec); - double b = OP_C(3).jsValue().toNumber(exec); - RETURN(jsNumber(a / b)); + JSValue left = OP_C(2).jsValue(); + JSValue right = OP_C(3).jsValue(); + double a = left.toNumber(exec); + double b = right.toNumber(exec); + JSValue result = jsNumber(a / b); + RETURN_WITH_PROFILING(result, { + updateResultProfileForBinaryArithOp(exec, pc, result, left, right); + }); } SLOW_PATH_DECL(slow_path_mod) @@ -449,10 +514,10 @@ SLOW_PATH_DECL(slow_path_typeof) RETURN(jsTypeStringForValue(exec, OP_C(2).jsValue())); } -SLOW_PATH_DECL(slow_path_is_object) +SLOW_PATH_DECL(slow_path_is_object_or_null) { BEGIN(); - RETURN(jsBoolean(jsIsObjectType(exec, OP_C(2).jsValue()))); + RETURN(jsBoolean(jsIsObjectTypeOrNull(exec, OP_C(2).jsValue()))); } SLOW_PATH_DECL(slow_path_is_function) @@ -480,11 +545,9 @@ SLOW_PATH_DECL(slow_path_del_by_val) uint32_t i; if (subscript.getUInt32(i)) couldDelete = baseObject->methodTable()->deletePropertyByIndex(baseObject, exec, i); - else if (isName(subscript)) - couldDelete = baseObject->methodTable()->deleteProperty(baseObject, exec, jsCast<NameInstance*>(subscript.asCell())->privateName()); else { CHECK_EXCEPTION(); - Identifier property(exec, subscript.toString(exec)->value(exec)); + auto property = subscript.toPropertyKey(exec); CHECK_EXCEPTION(); couldDelete = baseObject->methodTable()->deleteProperty(baseObject, exec, property); } @@ -510,11 +573,228 @@ SLOW_PATH_DECL(slow_path_to_primitive) SLOW_PATH_DECL(slow_path_enter) { BEGIN(); - ScriptExecutable* ownerExecutable = exec->codeBlock()->ownerExecutable(); - Heap::heap(ownerExecutable)->writeBarrier(ownerExecutable); + CodeBlock* codeBlock = exec->codeBlock(); + Heap::heap(codeBlock)->writeBarrier(codeBlock); END(); } -} // namespace JSC +SLOW_PATH_DECL(slow_path_get_enumerable_length) +{ + BEGIN(); + JSValue enumeratorValue = OP(2).jsValue(); + if (enumeratorValue.isUndefinedOrNull()) + RETURN(jsNumber(0)); + + JSPropertyNameEnumerator* enumerator = jsCast<JSPropertyNameEnumerator*>(enumeratorValue.asCell()); + + RETURN(jsNumber(enumerator->indexedLength())); +} + +SLOW_PATH_DECL(slow_path_has_indexed_property) +{ + BEGIN(); + JSObject* base = OP(2).jsValue().toObject(exec); + JSValue property = OP(3).jsValue(); + pc[4].u.arrayProfile->observeStructure(base->structure(vm)); + ASSERT(property.isUInt32()); + RETURN(jsBoolean(base->hasProperty(exec, property.asUInt32()))); +} + +SLOW_PATH_DECL(slow_path_has_structure_property) +{ + BEGIN(); + JSObject* base = OP(2).jsValue().toObject(exec); + JSValue property = OP(3).jsValue(); + ASSERT(property.isString()); + JSPropertyNameEnumerator* enumerator = jsCast<JSPropertyNameEnumerator*>(OP(4).jsValue().asCell()); + if (base->structure(vm)->id() == enumerator->cachedStructureID()) + RETURN(jsBoolean(true)); + RETURN(jsBoolean(base->hasProperty(exec, asString(property.asCell())->toIdentifier(exec)))); +} + +SLOW_PATH_DECL(slow_path_has_generic_property) +{ + BEGIN(); + JSObject* base = OP(2).jsValue().toObject(exec); + JSValue property = OP(3).jsValue(); + bool result; + if (property.isString()) + result = base->hasProperty(exec, asString(property.asCell())->toIdentifier(exec)); + else { + ASSERT(property.isUInt32()); + result = base->hasProperty(exec, property.asUInt32()); + } + RETURN(jsBoolean(result)); +} + +SLOW_PATH_DECL(slow_path_get_direct_pname) +{ + BEGIN(); + JSValue baseValue = OP_C(2).jsValue(); + JSValue property = OP(3).jsValue(); + ASSERT(property.isString()); + RETURN(baseValue.get(exec, asString(property)->toIdentifier(exec))); +} -#endif // ENABLE(JIT) || ENABLE(LLINT) +SLOW_PATH_DECL(slow_path_get_property_enumerator) +{ + BEGIN(); + JSValue baseValue = OP(2).jsValue(); + if (baseValue.isUndefinedOrNull()) + RETURN(JSPropertyNameEnumerator::create(vm)); + + JSObject* base = baseValue.toObject(exec); + + RETURN(propertyNameEnumerator(exec, base)); +} + +SLOW_PATH_DECL(slow_path_next_structure_enumerator_pname) +{ + BEGIN(); + JSPropertyNameEnumerator* enumerator = jsCast<JSPropertyNameEnumerator*>(OP(2).jsValue().asCell()); + uint32_t index = OP(3).jsValue().asUInt32(); + + JSString* propertyName = nullptr; + if (index < enumerator->endStructurePropertyIndex()) + propertyName = enumerator->propertyNameAtIndex(index); + RETURN(propertyName ? propertyName : jsNull()); +} + +SLOW_PATH_DECL(slow_path_next_generic_enumerator_pname) +{ + BEGIN(); + JSPropertyNameEnumerator* enumerator = jsCast<JSPropertyNameEnumerator*>(OP(2).jsValue().asCell()); + uint32_t index = OP(3).jsValue().asUInt32(); + + JSString* propertyName = nullptr; + if (enumerator->endStructurePropertyIndex() <= index && index < enumerator->endGenericPropertyIndex()) + propertyName = enumerator->propertyNameAtIndex(index); + RETURN(propertyName ? propertyName : jsNull()); +} + +SLOW_PATH_DECL(slow_path_to_index_string) +{ + BEGIN(); + RETURN(jsString(exec, Identifier::from(exec, OP(2).jsValue().asUInt32()).string())); +} + +SLOW_PATH_DECL(slow_path_profile_type_clear_log) +{ + BEGIN(); + vm.typeProfilerLog()->processLogEntries(ASCIILiteral("LLInt log full.")); + END(); +} + +SLOW_PATH_DECL(slow_path_assert) +{ + BEGIN(); + ASSERT_WITH_MESSAGE(OP(1).jsValue().asBoolean(), "JS assertion failed at line %d in:\n%s\n", pc[2].u.operand, exec->codeBlock()->sourceCodeForTools().data()); + END(); +} + +SLOW_PATH_DECL(slow_path_save) +{ + // Only save variables and temporary registers. The scope registers are included in them. + // But parameters are not included. Because the generator implementation replaces the values of parameters on each generator.next() call. + BEGIN(); + JSValue generator = OP(1).jsValue(); + GeneratorFrame* frame = nullptr; + JSValue value = generator.get(exec, exec->propertyNames().generatorFramePrivateName); + if (!value.isNull()) + frame = jsCast<GeneratorFrame*>(value); + else { + // FIXME: Once JSGenerator specialized object is introduced, this GeneratorFrame should be embeded into it to avoid allocations. + // https://bugs.webkit.org/show_bug.cgi?id=151545 + frame = GeneratorFrame::create(exec->vm(), exec->codeBlock()->numCalleeLocals()); + PutPropertySlot slot(generator, true, PutPropertySlot::PutById); + asObject(generator)->methodTable(exec->vm())->put(asObject(generator), exec, exec->propertyNames().generatorFramePrivateName, frame, slot); + } + unsigned liveCalleeLocalsIndex = pc[2].u.unsignedValue; + frame->save(exec, exec->codeBlock()->liveCalleeLocalsAtYield(liveCalleeLocalsIndex)); + END(); +} + +SLOW_PATH_DECL(slow_path_resume) +{ + BEGIN(); + JSValue generator = OP(1).jsValue(); + GeneratorFrame* frame = jsCast<GeneratorFrame*>(generator.get(exec, exec->propertyNames().generatorFramePrivateName)); + unsigned liveCalleeLocalsIndex = pc[2].u.unsignedValue; + frame->resume(exec, exec->codeBlock()->liveCalleeLocalsAtYield(liveCalleeLocalsIndex)); + END(); +} + +SLOW_PATH_DECL(slow_path_create_lexical_environment) +{ + BEGIN(); + int scopeReg = pc[2].u.operand; + JSScope* currentScope = exec->uncheckedR(scopeReg).Register::scope(); + SymbolTable* symbolTable = jsCast<SymbolTable*>(OP_C(3).jsValue()); + JSValue initialValue = OP_C(4).jsValue(); + ASSERT(initialValue == jsUndefined() || initialValue == jsTDZValue()); + JSScope* newScope = JSLexicalEnvironment::create(vm, exec->lexicalGlobalObject(), currentScope, symbolTable, initialValue); + RETURN(newScope); +} + +SLOW_PATH_DECL(slow_path_push_with_scope) +{ + BEGIN(); + JSObject* newScope = OP_C(2).jsValue().toObject(exec); + CHECK_EXCEPTION(); + + int scopeReg = pc[3].u.operand; + JSScope* currentScope = exec->uncheckedR(scopeReg).Register::scope(); + RETURN(JSWithScope::create(exec, newScope, currentScope)); +} + +SLOW_PATH_DECL(slow_path_resolve_scope) +{ + BEGIN(); + const Identifier& ident = exec->codeBlock()->identifier(pc[3].u.operand); + JSScope* scope = exec->uncheckedR(pc[2].u.operand).Register::scope(); + JSValue resolvedScope = JSScope::resolve(exec, scope, ident); + + ResolveType resolveType = static_cast<ResolveType>(pc[4].u.operand); + + // ModuleVar does not keep the scope register value alive in DFG. + ASSERT(resolveType != ModuleVar); + + if (resolveType == UnresolvedProperty || resolveType == UnresolvedPropertyWithVarInjectionChecks) { + if (JSGlobalLexicalEnvironment* globalLexicalEnvironment = jsDynamicCast<JSGlobalLexicalEnvironment*>(resolvedScope)) { + if (resolveType == UnresolvedProperty) + pc[4].u.operand = GlobalLexicalVar; + else + pc[4].u.operand = GlobalLexicalVarWithVarInjectionChecks; + pc[6].u.pointer = globalLexicalEnvironment; + } else if (JSGlobalObject* globalObject = jsDynamicCast<JSGlobalObject*>(resolvedScope)) { + if (globalObject->hasProperty(exec, ident)) { + if (resolveType == UnresolvedProperty) + pc[4].u.operand = GlobalProperty; + else + pc[4].u.operand = GlobalPropertyWithVarInjectionChecks; + + pc[6].u.pointer = globalObject; + } + } + } + + RETURN(resolvedScope); +} + +SLOW_PATH_DECL(slow_path_copy_rest) +{ + BEGIN(); + unsigned arraySize = OP_C(2).jsValue().asUInt32(); + if (!arraySize) { + ASSERT(!jsCast<JSArray*>(OP(1).jsValue())->length()); + END(); + } + JSArray* array = jsCast<JSArray*>(OP(1).jsValue()); + ASSERT(arraySize == array->length()); + unsigned numParamsToSkip = pc[3].u.unsignedValue; + for (unsigned i = 0; i < arraySize; i++) + array->putDirectIndex(exec, i, exec->uncheckedArgument(i + numParamsToSkip)); + END(); +} + +} // namespace JSC |