[ia32,root] Add indirect calls and jumps through virtual register

This adds a temporary mechanism for isolate-independent calls and
jumps.  The problem was that - as ia32 doesn't have a scratch register
- Call and Jump cannot call through a register. This CL adds a
so-called virtual register (= a pointer-sized field) on IsolateData.

The virtual register can be removed once pc-relative calls are
implemented and all builtins have been embedded.

Bug: v8:6666
Change-Id: I1f9d8a25643fad0b3919dd813dbe219d20fcc6bc
Reviewed-on: https://chromium-review.googlesource.com/c/1282991
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Reviewed-by: Sigurd Schneider <sigurds@chromium.org>
Reviewed-by: Igor Sheludko <ishell@chromium.org>
Cr-Commit-Position: refs/heads/master@{#56693}
This commit is contained in:
Jakob Gruber 2018-10-16 13:36:10 +02:00 committed by Commit Bot
parent 7d87193148
commit 650703557a
3 changed files with 484 additions and 19 deletions

View File

@ -351,14 +351,435 @@ bool Builtins::IsIsolateIndependent(int index) {
// ia32 is a work-in-progress. This will let us make builtins
// isolate-independent one-by-one.
switch (index) {
case kArrayBufferConstructor:
case kArrayBufferConstructor_DoNotInitialize:
case kArrayBufferIsView:
case kArrayBufferPrototypeGetByteLength:
case kArrayBufferPrototypeSlice:
case kArrayConcat:
case kArrayIncludesHoleyDoubles:
case kArrayIncludesPackedDoubles:
case kArrayIndexOfHoleyDoubles:
case kArrayIndexOfPackedDoubles:
case kArrayPop:
case kArrayPrototypeFill:
case kArrayPush:
case kArrayShift:
case kArrayUnshift:
case kAsyncFunctionConstructor:
case kAsyncFunctionLazyDeoptContinuation:
case kAsyncGeneratorFunctionConstructor:
case kAtomicsIsLockFree:
case kAtomicsNotify:
case kAtomicsWait:
case kAtomicsWake:
case kBigIntAsIntN:
case kBigIntAsUintN:
case kBigIntConstructor:
case kBigIntPrototypeToLocaleString:
case kBigIntPrototypeToString:
case kBigIntPrototypeValueOf:
case kBooleanConstructor:
case kCallBoundFunction:
case kCallForwardVarargs:
case kCallFunctionForwardVarargs:
case kCallSitePrototypeGetColumnNumber:
case kCallSitePrototypeGetEvalOrigin:
case kCallSitePrototypeGetFileName:
case kCallSitePrototypeGetFunction:
case kCallSitePrototypeGetFunctionName:
case kCallSitePrototypeGetLineNumber:
case kCallSitePrototypeGetMethodName:
case kCallSitePrototypeGetPosition:
case kCallSitePrototypeGetScriptNameOrSourceURL:
case kCallSitePrototypeGetThis:
case kCallSitePrototypeGetTypeName:
case kCallSitePrototypeIsAsync:
case kCallSitePrototypeIsConstructor:
case kCallSitePrototypeIsEval:
case kCallSitePrototypeIsNative:
case kCallSitePrototypeIsToplevel:
case kCallSitePrototypeToString:
case kCallVarargs:
case kCanUseSameAccessor20ATDictionaryElements:
case kCanUseSameAccessor25ATGenericElementsAccessor:
case kCollatorConstructor:
case kCollatorInternalCompare:
case kCollatorPrototypeCompare:
case kCollatorPrototypeResolvedOptions:
case kCollatorSupportedLocalesOf:
case kConsoleAssert:
case kConsoleClear:
case kConsoleContext:
case kConsoleCount:
case kConsoleCountReset:
case kConsoleDebug:
case kConsoleDir:
case kConsoleDirXml:
case kConsoleError:
case kConsoleGroup:
case kConsoleGroupCollapsed:
case kConsoleGroupEnd:
case kConsoleInfo:
case kConsoleLog:
case kConsoleProfile:
case kConsoleProfileEnd:
case kConsoleTable:
case kConsoleTime:
case kConsoleTimeEnd:
case kConsoleTimeLog:
case kConsoleTimeStamp:
case kConsoleTrace:
case kConsoleWarn:
case kConstructBoundFunction:
case kConstructedNonConstructable:
case kConstructForwardVarargs:
case kConstructFunction:
case kConstructFunctionForwardVarargs:
case kConstructVarargs:
case kContinueToCodeStubBuiltin:
case kContinueToCodeStubBuiltinWithResult:
case kContinueToJavaScriptBuiltin:
case kContinueToJavaScriptBuiltinWithResult:
case kDataViewConstructor:
case kDateConstructor:
case kDateNow:
case kDateParse:
case kDatePrototypeGetYear:
case kDatePrototypeSetDate:
case kDatePrototypeSetFullYear:
case kDatePrototypeSetHours:
case kDatePrototypeSetMilliseconds:
case kDatePrototypeSetMinutes:
case kDatePrototypeSetMonth:
case kDatePrototypeSetSeconds:
case kDatePrototypeSetTime:
case kDatePrototypeSetUTCDate:
case kDatePrototypeSetUTCFullYear:
case kDatePrototypeSetUTCHours:
case kDatePrototypeSetUTCMilliseconds:
case kDatePrototypeSetUTCMinutes:
case kDatePrototypeSetUTCMonth:
case kDatePrototypeSetUTCSeconds:
case kDatePrototypeSetYear:
case kDatePrototypeToDateString:
case kDatePrototypeToISOString:
case kDatePrototypeToJson:
case kDatePrototypeToLocaleDateString:
case kDatePrototypeToLocaleString:
case kDatePrototypeToLocaleTimeString:
case kDatePrototypeToString:
case kDatePrototypeToTimeString:
case kDatePrototypeToUTCString:
case kDateTimeFormatConstructor:
case kDateTimeFormatInternalFormat:
case kDateTimeFormatPrototypeFormat:
case kDateTimeFormatPrototypeFormatToParts:
case kDateTimeFormatPrototypeResolvedOptions:
case kDateTimeFormatSupportedLocalesOf:
case kDateUTC:
case kDoubleToI:
case kEmptyFunction:
case kErrorCaptureStackTrace:
case kErrorConstructor:
case kErrorPrototypeToString:
case kExtraWideHandler:
case kForInContinueExtraWideHandler:
case kForInContinueHandler:
case kForInContinueWideHandler:
case kForInPrepareExtraWideHandler:
case kForInPrepareHandler:
case kForInPrepareWideHandler:
case kForInStepExtraWideHandler:
case kForInStepHandler:
case kForInStepWideHandler:
case kFunctionConstructor:
case kFunctionPrototypeApply:
case kFunctionPrototypeBind:
case kFunctionPrototypeCall:
case kFunctionPrototypeToString:
case kGeneratorFunctionConstructor:
case kGenericBuiltinTest22UT12ATHeapObject5ATSmi:
case kGenericBuiltinTest5ATSmi:
case kGlobalDecodeURI:
case kGlobalDecodeURIComponent:
case kGlobalEncodeURI:
case kGlobalEncodeURIComponent:
case kGlobalEscape:
case kGlobalEval:
case kGlobalUnescape:
case kHandleApiCall:
case kHandleApiCallAsConstructor:
case kHandleApiCallAsFunction:
case kIllegal:
case kInstantiateAsmJs:
case kInternalArrayConstructor:
case kInterpreterOnStackReplacement:
case kInterpreterPushArgsThenCall:
case kInterpreterPushArgsThenCallWithFinalSpread:
case kInterpreterPushArgsThenConstruct:
case kInterpreterPushArgsThenConstructWithFinalSpread:
case kInterpreterPushUndefinedAndArgsThenCall:
case kInterruptCheck:
case kIsPromise:
case kIsTraceCategoryEnabled:
case kJSConstructEntryTrampoline:
case kJSEntryTrampoline:
case kJsonParse:
case kJsonStringify:
case kJumpConstantExtraWideHandler:
case kJumpConstantHandler:
case kJumpConstantWideHandler:
case kJumpExtraWideHandler:
case kJumpHandler:
case kJumpIfFalseConstantExtraWideHandler:
case kJumpIfFalseConstantHandler:
case kJumpIfFalseConstantWideHandler:
case kJumpIfFalseExtraWideHandler:
case kJumpIfFalseHandler:
case kJumpIfFalseWideHandler:
case kJumpIfJSReceiverConstantExtraWideHandler:
case kJumpIfJSReceiverConstantHandler:
case kJumpIfJSReceiverConstantWideHandler:
case kJumpIfJSReceiverExtraWideHandler:
case kJumpIfJSReceiverHandler:
case kJumpIfJSReceiverWideHandler:
case kJumpIfNotNullConstantExtraWideHandler:
case kJumpIfNotNullConstantHandler:
case kJumpIfNotNullConstantWideHandler:
case kJumpIfNotNullExtraWideHandler:
case kJumpIfNotNullHandler:
case kJumpIfNotNullWideHandler:
case kJumpIfNotUndefinedConstantExtraWideHandler:
case kJumpIfNotUndefinedConstantHandler:
case kJumpIfNotUndefinedConstantWideHandler:
case kJumpIfNotUndefinedExtraWideHandler:
case kJumpIfNotUndefinedHandler:
case kJumpIfNotUndefinedWideHandler:
case kJumpIfNullConstantExtraWideHandler:
case kJumpIfNullConstantHandler:
case kJumpIfNullConstantWideHandler:
case kJumpIfNullExtraWideHandler:
case kJumpIfNullHandler:
case kJumpIfNullWideHandler:
case kJumpIfTrueConstantExtraWideHandler:
case kJumpIfTrueConstantHandler:
case kJumpIfTrueConstantWideHandler:
case kJumpIfTrueExtraWideHandler:
case kJumpIfTrueHandler:
case kJumpIfTrueWideHandler:
case kJumpIfUndefinedConstantExtraWideHandler:
case kJumpIfUndefinedConstantHandler:
case kJumpIfUndefinedConstantWideHandler:
case kJumpIfUndefinedExtraWideHandler:
case kJumpIfUndefinedHandler:
case kJumpIfUndefinedWideHandler:
case kJumpWideHandler:
case kLdaConstantExtraWideHandler:
case kLdaConstantHandler:
case kLdaConstantWideHandler:
case kLdaContextSlotExtraWideHandler:
case kLdaContextSlotHandler:
case kLdaContextSlotWideHandler:
case kLdaCurrentContextSlotExtraWideHandler:
case kLdaCurrentContextSlotHandler:
case kLdaCurrentContextSlotWideHandler:
case kLdaFalseHandler:
case kLdaImmutableContextSlotExtraWideHandler:
case kLdaImmutableContextSlotHandler:
case kLdaImmutableContextSlotWideHandler:
case kLdaImmutableCurrentContextSlotExtraWideHandler:
case kLdaImmutableCurrentContextSlotHandler:
case kLdaImmutableCurrentContextSlotWideHandler:
case kLdaModuleVariableExtraWideHandler:
case kLdaModuleVariableHandler:
case kLdaModuleVariableWideHandler:
case kLdaNullHandler:
case kLdarExtraWideHandler:
case kLdarHandler:
case kLdarWideHandler:
case kLdaSmiExtraWideHandler:
case kLdaSmiHandler:
case kLdaSmiWideHandler:
case kLdaTheHoleHandler:
case kLdaTrueHandler:
case kLdaUndefinedHandler:
case kLdaZeroHandler:
case kListFormatConstructor:
case kListFormatPrototypeResolvedOptions:
case kListFormatSupportedLocalesOf:
case kLoad20ATDictionaryElements:
case kLoad23ATFastPackedSmiElements:
case kLoad25ATFastSmiOrObjectElements:
case kLoadFixedElement16ATFixedInt8Array:
case kLoadFixedElement17ATFixedInt16Array:
case kLoadFixedElement17ATFixedUint8Array:
case kLoadFixedElement18ATFixedUint16Array:
case kLoadFixedElement24ATFixedUint8ClampedArray:
case kLoadIC_StringLength:
case kLoadIC_StringWrapperLength:
case kLocaleConstructor:
case kLocalePrototypeBaseName:
case kLocalePrototypeCalendar:
case kLocalePrototypeCaseFirst:
case kLocalePrototypeCollation:
case kLocalePrototypeHourCycle:
case kLocalePrototypeLanguage:
case kLocalePrototypeMaximize:
case kLocalePrototypeMinimize:
case kLocalePrototypeNumberingSystem:
case kLocalePrototypeNumeric:
case kLocalePrototypeRegion:
case kLocalePrototypeScript:
case kLocalePrototypeToString:
case kLogicalNotHandler:
case kMakeError:
case kMakeRangeError:
case kMakeSyntaxError:
case kMakeTypeError:
case kMakeURIError:
case kMapPrototypeClear:
case kMathHypot:
case kMathPowInternal:
case kMovExtraWideHandler:
case kMovHandler:
case kMovWideHandler:
case kNotifyDeoptimized:
case kNumberFormatConstructor:
case kNumberFormatInternalFormatNumber:
case kNumberFormatPrototypeFormatNumber:
case kNumberFormatPrototypeFormatToParts:
case kNumberFormatPrototypeResolvedOptions:
case kNumberFormatSupportedLocalesOf:
case kNumberPrototypeToExponential:
case kNumberPrototypeToFixed:
case kNumberPrototypeToLocaleString:
case kNumberPrototypeToPrecision:
case kNumberPrototypeToString:
case kObjectDefineGetter:
case kObjectDefineProperties:
case kObjectDefineProperty:
case kObjectDefineSetter:
case kObjectFreeze:
case kObjectGetOwnPropertyDescriptors:
case kObjectGetOwnPropertySymbols:
case kObjectGetPrototypeOf:
case kObjectIsExtensible:
case kObjectIsFrozen:
case kObjectIsSealed:
case kObjectLookupGetter:
case kObjectLookupSetter:
case kObjectPreventExtensions:
case kObjectPrototypeGetProto:
case kObjectPrototypePropertyIsEnumerable:
case kObjectPrototypeSetProto:
case kObjectSeal:
case kObjectSetPrototypeOf:
case kOrderedHashTableHealIndex:
case kPluralRulesConstructor:
case kPluralRulesPrototypeResolvedOptions:
case kPluralRulesPrototypeSelect:
case kPluralRulesSupportedLocalesOf:
case kPopContextExtraWideHandler:
case kPopContextHandler:
case kPopContextWideHandler:
case kPushContextExtraWideHandler:
case kPushContextHandler:
case kPushContextWideHandler:
case kRecordWrite:
case kReflectApply:
case kReflectConstruct:
case kReflectDefineProperty:
case kReflectDeleteProperty:
case kReflectGet:
case kReflectGetOwnPropertyDescriptor:
case kReflectGetPrototypeOf:
case kReflectIsExtensible:
case kReflectOwnKeys:
case kReflectPreventExtensions:
case kReflectSet:
case kReflectSetPrototypeOf:
case kRegExpCapture1Getter:
case kRegExpCapture2Getter:
case kRegExpCapture3Getter:
case kRegExpCapture4Getter:
case kRegExpCapture5Getter:
case kRegExpCapture6Getter:
case kRegExpCapture7Getter:
case kRegExpCapture8Getter:
case kRegExpCapture9Getter:
case kRegExpInputGetter:
case kRegExpInputSetter:
case kRegExpLastMatchGetter:
case kRegExpLastParenGetter:
case kRegExpLeftContextGetter:
case kRegExpPrototypeToString:
case kRegExpRightContextGetter:
case kRelativeTimeFormatConstructor:
case kRelativeTimeFormatPrototypeFormat:
case kRelativeTimeFormatPrototypeFormatToParts:
case kRelativeTimeFormatPrototypeResolvedOptions:
case kRelativeTimeFormatSupportedLocalesOf:
case kResumeGeneratorTrampoline:
case kSegmenterConstructor:
case kSegmenterPrototypeResolvedOptions:
case kSegmenterSupportedLocalesOf:
case kSetPendingMessageHandler:
case kSetPrototypeClear:
case kSharedArrayBufferPrototypeGetByteLength:
case kSharedArrayBufferPrototypeSlice:
case kStackCheck:
case kStaContextSlotExtraWideHandler:
case kStaContextSlotHandler:
case kStaContextSlotWideHandler:
case kStaCurrentContextSlotExtraWideHandler:
case kStaCurrentContextSlotHandler:
case kStaCurrentContextSlotWideHandler:
case kStarExtraWideHandler:
case kStarHandler:
case kStarWideHandler:
case kStore19ATTempArrayElements:
case kStore20ATFastDoubleElements:
case kStore23ATFastPackedSmiElements:
case kStore25ATFastSmiOrObjectElements:
case kStoreFixedElement16ATFixedInt8Array:
case kStoreFixedElement17ATFixedInt16Array:
case kStoreFixedElement17ATFixedUint8Array:
case kStoreFixedElement18ATFixedUint16Array:
case kStoreFixedElement19ATFixedFloat32Array:
case kStoreFixedElement19ATFixedFloat64Array:
case kStoreFixedElement20ATFixedBigInt64Array:
case kStoreFixedElement21ATFixedBigUint64Array:
case kStoreFixedElement24ATFixedUint8ClampedArray:
case kStrictPoisonPillThrower:
case kStringFromCodePoint:
case kStringPrototypeEndsWith:
case kStringPrototypeLastIndexOf:
case kStringPrototypeLocaleCompare:
case kStringPrototypeNormalizeIntl:
case kStringPrototypeStartsWith:
case kStringPrototypeToLocaleLowerCase:
case kStringPrototypeToLocaleUpperCase:
case kStringPrototypeToUpperCaseIntl:
case kStringRaw:
case kSwitchOnGeneratorStateExtraWideHandler:
case kSwitchOnGeneratorStateHandler:
case kSwitchOnGeneratorStateWideHandler:
case kSwitchOnSmiNoFeedbackExtraWideHandler:
case kSwitchOnSmiNoFeedbackHandler:
case kSwitchOnSmiNoFeedbackWideHandler:
case kSymbolConstructor:
case kSymbolFor:
case kSymbolKeyFor:
case kTestHelperPlus1:
case kTestHelperPlus2:
case kTestNullHandler:
case kTestReferenceEqualExtraWideHandler:
case kTestReferenceEqualHandler:
case kTestReferenceEqualWideHandler:
case kTestTypeOfHandler:
case kTestUndefinedHandler:
case kTestUndetectableHandler:
case kThrowWasmTrapDivByZero:
case kThrowWasmTrapDivUnrepresentable:
case kThrowWasmTrapFloatUnrepresentable:
@ -368,6 +789,30 @@ bool Builtins::IsIsolateIndependent(int index) {
case kThrowWasmTrapRemByZero:
case kThrowWasmTrapUnalignedAccess:
case kThrowWasmTrapUnreachable:
case kTrace:
case kTypedArrayPrototypeBuffer:
case kTypedArrayPrototypeCopyWithin:
case kTypedArrayPrototypeFill:
case kTypedArrayPrototypeIncludes:
case kTypedArrayPrototypeIndexOf:
case kTypedArrayPrototypeLastIndexOf:
case kTypedArrayPrototypeReverse:
case kTypeof:
case kTypeOfHandler:
case kUnsupportedThrower:
case kV8BreakIteratorConstructor:
case kV8BreakIteratorInternalAdoptText:
case kV8BreakIteratorInternalBreakType:
case kV8BreakIteratorInternalCurrent:
case kV8BreakIteratorInternalFirst:
case kV8BreakIteratorInternalNext:
case kV8BreakIteratorPrototypeAdoptText:
case kV8BreakIteratorPrototypeBreakType:
case kV8BreakIteratorPrototypeCurrent:
case kV8BreakIteratorPrototypeFirst:
case kV8BreakIteratorPrototypeNext:
case kV8BreakIteratorPrototypeResolvedOptions:
case kV8BreakIteratorSupportedLocalesOf:
case kWasmAllocateHeapNumber:
case kWasmCallJavaScript:
case kWasmCompileLazy:
@ -375,6 +820,11 @@ bool Builtins::IsIsolateIndependent(int index) {
case kWasmStackGuard:
case kWasmThrow:
case kWasmToNumber:
case kWeakFactoryCleanupIteratorNext:
case kWeakFactoryConstructor:
case kWeakFactoryMakeCell:
case kWeakMapLookupHashIndex:
case kWideHandler:
return true;
default:
return false;

View File

@ -1891,15 +1891,20 @@ void TurboAssembler::CallCFunction(Register function, int num_arguments) {
void TurboAssembler::Call(Handle<Code> code_object, RelocInfo::Mode rmode) {
if (FLAG_embedded_builtins) {
// TODO(jgruber): Pc-relative builtin-to-builtin calls.
if (root_array_available_ && options().isolate_independent_code) {
// TODO(jgruber): There's no scratch register on ia32. Any call that
// requires loading a code object from the builtins constant table must:
// 1) spill two scratch registers, 2) load the target into scratch1, 3)
// store the target into a virtual register on the isolate using scratch2,
// 4) restore both scratch registers, and finally 5) call through the
// virtual register. All affected call sites should vanish once all
// builtins are embedded on ia32.
UNREACHABLE();
if (root_array_available_ && ShouldGenerateIsolateIndependentCode() &&
Builtins::IsBuiltin(*code_object)) {
// Since we don't have a scratch register available we call through a
// so-called virtual register.
// TODO(v8:6666): Remove once pc-relative jumps are supported on ia32.
Assembler::AllowExplicitEbxAccessScope read_only_access(this);
Operand virtual_call_target_register(
kRootRegister,
IsolateData::kVirtualCallTargetRegisterOffset - kRootRegisterBias);
Move(virtual_call_target_register, Immediate(code_object));
add(virtual_call_target_register,
Immediate(Code::kHeaderSize - kHeapObjectTag));
call(virtual_call_target_register);
return;
} else if (options().inline_offheap_trampolines) {
int builtin_index = Builtins::kNoBuiltinId;
if (isolate()->builtins()->IsBuiltinHandle(code_object, &builtin_index) &&
@ -1921,15 +1926,20 @@ void TurboAssembler::Call(Handle<Code> code_object, RelocInfo::Mode rmode) {
void TurboAssembler::Jump(Handle<Code> code_object, RelocInfo::Mode rmode) {
if (FLAG_embedded_builtins) {
// TODO(jgruber): Pc-relative builtin-to-builtin calls.
if (root_array_available_ && options().isolate_independent_code) {
// TODO(jgruber): There's no scratch register on ia32. Any call that
// requires loading a code object from the builtins constant table must:
// 1) spill two scratch registers, 2) load the target into scratch1, 3)
// store the target into a virtual register on the isolate using scratch2,
// 4) restore both scratch registers, and finally 5) call through the
// virtual register. All affected call sites should vanish once all
// builtins are embedded on ia32.
UNREACHABLE();
if (root_array_available_ && ShouldGenerateIsolateIndependentCode() &&
Builtins::IsBuiltin(*code_object)) {
// Since we don't have a scratch register available we call through a
// so-called virtual register.
// TODO(v8:6666): Remove once pc-relative jumps are supported on ia32.
Assembler::AllowExplicitEbxAccessScope read_only_access(this);
Operand virtual_call_target_register(
kRootRegister,
IsolateData::kVirtualCallTargetRegisterOffset - kRootRegisterBias);
Move(virtual_call_target_register, Immediate(code_object));
add(virtual_call_target_register,
Immediate(Code::kHeaderSize - kHeapObjectTag));
jmp(virtual_call_target_register);
return;
} else if (options().inline_offheap_trampolines) {
int builtin_index = Builtins::kNoBuiltinId;
if (isolate()->builtins()->IsBuiltinHandle(code_object, &builtin_index) &&

View File

@ -39,7 +39,8 @@ class IsolateData final {
V(kBuiltinsTableEndOffset, 0) \
/* magic_number_ */ \
V(kMagicNumberOffset, kIntptrSize) \
V(kMagicNumberEndOffset, 0) \
/* virtual_call_target_register_ */ \
V(kVirtualCallTargetRegisterOffset, kPointerSize) \
/* Total size. */ \
V(kSize, 0)
@ -79,6 +80,10 @@ class IsolateData final {
// TODO(v8:6666): Remove once the root register is fully supported on ia32.
const intptr_t magic_number_ = kRootRegisterSentinel;
// For isolate-independent calls on ia32.
// TODO(v8:6666): Remove once pc-relative jumps are supported on ia32.
void* virtual_call_target_register_ = nullptr;
V8_INLINE static void AssertPredictableLayout();
friend class Isolate;