Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
P
Pyston
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Boxiang Sun
Pyston
Commits
fc111bc5
Commit
fc111bc5
authored
Jul 27, 2014
by
Travis Hance
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
ported objmodel.cpp to use rewriter2 exclusively, deprecates rewriter1
parent
a5258c49
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
1076 additions
and
808 deletions
+1076
-808
src/asm_writing/assembler.cpp
src/asm_writing/assembler.cpp
+0
-1
src/asm_writing/rewriter2.cpp
src/asm_writing/rewriter2.cpp
+268
-47
src/asm_writing/rewriter2.h
src/asm_writing/rewriter2.h
+23
-3
src/core/cfg.cpp
src/core/cfg.cpp
+1
-1
src/core/types.h
src/core/types.h
+9
-5
src/runtime/builtin_modules/builtins.cpp
src/runtime/builtin_modules/builtins.cpp
+3
-3
src/runtime/objmodel.cpp
src/runtime/objmodel.cpp
+759
-734
src/runtime/objmodel.h
src/runtime/objmodel.h
+10
-11
src/runtime/types.cpp
src/runtime/types.cpp
+3
-3
No files found.
src/asm_writing/assembler.cpp
View file @
fc111bc5
...
...
@@ -477,7 +477,6 @@ void Assembler::cmp(Register reg1, Register reg2) {
reg1_idx
-=
8
;
}
if
(
reg2_idx
>=
8
)
{
trap
();
rex
|=
REX_B
;
reg2_idx
-=
8
;
}
...
...
src/asm_writing/rewriter2.cpp
View file @
fc111bc5
...
...
@@ -51,9 +51,8 @@ Location Location::forArg(int argnum) {
default:
break
;
}
RELEASE_ASSERT
(
0
,
"the following is untested"
);
// int offset = (argnum - 6) * 8;
// return Location(Stack, offset);
int
offset
=
(
argnum
-
6
)
*
8
;
return
Location
(
Stack
,
offset
);
}
assembler
::
Register
Location
::
asRegister
()
const
{
...
...
@@ -80,6 +79,9 @@ bool Location::isClobberedByCall() const {
if
(
type
==
Constant
)
return
false
;
if
(
type
==
Stack
)
return
false
;
RELEASE_ASSERT
(
0
,
"%d"
,
type
);
}
...
...
@@ -95,7 +97,7 @@ void Location::dump() const {
}
if
(
type
==
Scratch
)
{
printf
(
"scratch(%d)
\n
"
,
s
tack
_offset
);
printf
(
"scratch(%d)
\n
"
,
s
cratch
_offset
);
return
;
}
...
...
@@ -104,25 +106,69 @@ void Location::dump() const {
return
;
}
if
(
type
==
Stack
)
{
printf
(
"stack(%d)
\n
"
,
stack_offset
);
return
;
}
RELEASE_ASSERT
(
0
,
"%d"
,
type
);
}
RewriterVarUsage2
::
RewriterVarUsage2
(
RewriterVar2
*
var
)
:
var
(
var
),
done_using
(
false
)
{
var
->
incUse
();
assert
(
var
->
rewriter
);
}
void
RewriterVarUsage2
::
addAttrGuard
(
int
offset
,
uint64_t
val
)
{
void
RewriterVarUsage2
::
addGuard
(
uint64_t
val
)
{
assertValid
();
Rewriter2
*
rewriter
=
var
->
rewriter
;
assembler
::
Assembler
*
assembler
=
rewriter
->
assembler
;
assert
(
!
rewriter
->
done_guarding
&&
"too late to add a guard!"
);
assembler
::
Register
this_reg
=
var
->
getInReg
();
if
(
val
<
(
-
1L
<<
31
)
||
val
>=
(
1L
<<
31
)
-
1
)
{
assembler
::
Register
reg
=
rewriter
->
allocReg
(
Location
::
any
());
assembler
->
mov
(
assembler
::
Immediate
(
val
),
reg
);
assembler
->
cmp
(
this_reg
,
reg
);
}
else
{
assembler
->
cmp
(
this_reg
,
assembler
::
Immediate
(
val
));
}
assembler
->
jne
(
assembler
::
JumpDestination
::
fromStart
(
rewriter
->
rewrite
->
getSlotSize
()));
}
void
RewriterVarUsage2
::
addGuardNotEq
(
uint64_t
val
)
{
assertValid
();
Rewriter2
*
rewriter
=
var
->
rewriter
;
assembler
::
Assembler
*
assembler
=
rewriter
->
assembler
;
assert
(
!
rewriter
->
done_guarding
&&
"too late to add a guard!"
);
assembler
::
Register
this_reg
=
var
->
getInReg
();
if
(
val
<
(
-
1L
<<
31
)
||
val
>=
(
1L
<<
31
)
-
1
)
{
assembler
::
Register
reg
=
rewriter
->
allocReg
(
Location
::
any
());
assembler
->
mov
(
assembler
::
Immediate
(
val
),
reg
);
assembler
->
cmp
(
this_reg
,
reg
);
}
else
{
assembler
->
cmp
(
this_reg
,
assembler
::
Immediate
(
val
));
}
assembler
->
je
(
assembler
::
JumpDestination
::
fromStart
(
rewriter
->
rewrite
->
getSlotSize
()));
}
void
RewriterVarUsage2
::
addAttrGuard
(
int
offset
,
uint64_t
val
)
{
assertValid
();
Rewriter2
*
rewriter
=
var
->
rewriter
;
assembler
::
Assembler
*
assembler
=
rewriter
->
assembler
;
assert
(
!
rewriter
->
done_guarding
&&
"too late to add a guard!"
);
assembler
::
Register
this_reg
=
var
->
getInReg
();
if
(
val
<
(
-
1L
<<
31
)
||
val
>=
(
1L
<<
31
)
-
1
)
{
assembler
::
Register
reg
=
rewriter
->
allocReg
(
Location
::
any
());
assert
(
reg
!=
this_reg
);
assembler
->
mov
(
assembler
::
Immediate
(
val
),
reg
);
assembler
->
cmp
(
assembler
::
Indirect
(
this_reg
,
offset
),
reg
);
}
else
{
...
...
@@ -148,6 +194,51 @@ RewriterVarUsage2 RewriterVarUsage2::getAttr(int offset, KillFlag kill, Location
return
std
::
move
(
newvar
);
}
RewriterVarUsage2
RewriterVarUsage2
::
cmp
(
AST_TYPE
::
AST_TYPE
cmp_type
,
RewriterVarUsage2
other
,
Location
dest
)
{
assertValid
();
assembler
::
Register
this_reg
=
var
->
getInReg
();
assembler
::
Register
other_reg
=
other
.
var
->
getInReg
();
assert
(
this_reg
!=
other_reg
);
// TODO how do we ensure this?
Rewriter2
*
rewriter
=
var
->
rewriter
;
assembler
::
Register
newvar_reg
=
rewriter
->
allocReg
(
dest
);
RewriterVarUsage2
newvar
=
rewriter
->
createNewVar
(
newvar_reg
);
rewriter
->
assembler
->
cmp
(
this_reg
,
newvar_reg
);
switch
(
cmp_type
)
{
case
AST_TYPE
:
:
Eq
:
rewriter
->
assembler
->
sete
(
newvar_reg
);
break
;
case
AST_TYPE
:
:
NotEq
:
rewriter
->
assembler
->
setne
(
newvar_reg
);
break
;
default:
RELEASE_ASSERT
(
0
,
"%d"
,
cmp_type
);
}
other
.
setDoneUsing
();
return
std
::
move
(
newvar
);
}
RewriterVarUsage2
RewriterVarUsage2
::
toBool
(
KillFlag
kill
,
Location
dest
)
{
assertValid
();
assembler
::
Register
this_reg
=
var
->
getInReg
();
Rewriter2
*
rewriter
=
var
->
rewriter
;
if
(
kill
==
Kill
)
{
setDoneUsing
();
}
rewriter
->
assembler
->
test
(
this_reg
,
this_reg
);
assembler
::
Register
result_reg
=
rewriter
->
allocReg
(
dest
);
rewriter
->
assembler
->
setnz
(
result_reg
);
RewriterVarUsage2
result
=
rewriter
->
createNewVar
(
result_reg
);
return
result
;
}
void
RewriterVarUsage2
::
setAttr
(
int
offset
,
RewriterVarUsage2
val
)
{
assertValid
();
var
->
rewriter
->
assertChangesOk
();
...
...
@@ -179,6 +270,15 @@ void RewriterVarUsage2::setDoneUsing() {
var
=
NULL
;
}
bool
RewriterVarUsage2
::
isDoneUsing
()
{
return
done_using
;
}
void
RewriterVarUsage2
::
ensureDoneUsing
()
{
if
(
!
done_using
)
setDoneUsing
();
}
RewriterVarUsage2
::
RewriterVarUsage2
(
RewriterVarUsage2
&&
usage
)
{
assert
(
!
usage
.
done_using
);
assert
(
usage
.
var
!=
NULL
);
...
...
@@ -260,7 +360,7 @@ assembler::Register RewriterVar2::getInReg(Location dest) {
assert
(
locations
.
size
()
==
1
);
Location
l
(
*
locations
.
begin
());
assert
(
l
.
type
==
Location
::
Scratch
);
assert
(
l
.
type
==
Location
::
Scratch
||
l
.
type
==
Location
::
Stack
);
assembler
::
Register
reg
=
rewriter
->
allocReg
(
dest
);
...
...
@@ -362,7 +462,6 @@ RewriterVarUsage2 Rewriter2::getArg(int argnum) {
assert
(
argnum
>=
0
&&
argnum
<
args
.
size
());
RewriterVar2
*
var
=
args
[
argnum
];
var
->
incUse
();
return
RewriterVarUsage2
(
var
);
}
...
...
@@ -377,7 +476,11 @@ void Rewriter2::trap() {
RewriterVarUsage2
Rewriter2
::
loadConst
(
int64_t
val
,
Location
dest
)
{
if
(
val
>=
(
-
1L
<<
31
)
&&
val
<
(
1L
<<
31
)
-
1
)
{
Location
l
(
Location
::
Constant
,
val
);
return
createNewVar
(
l
);
RewriterVar2
*&
var
=
vars_by_location
[
l
];
if
(
!
var
)
{
var
=
new
RewriterVar2
(
this
,
l
);
}
return
RewriterVarUsage2
(
var
);
}
assembler
::
Register
reg
=
allocReg
(
dest
);
...
...
@@ -410,7 +513,9 @@ static const Location caller_save_registers[]{
};
RewriterVarUsage2
Rewriter2
::
call
(
bool
can_call_into_python
,
void
*
func_addr
,
std
::
vector
<
RewriterVarUsage2
>
args
)
{
assert
(
!
can_call_into_python
);
// TODO figure out why this is here -- what needs to be done differently
// if can_call_into_python is true?
// assert(!can_call_into_python);
assertChangesOk
();
...
...
@@ -461,16 +566,6 @@ RewriterVarUsage2 Rewriter2::call(bool can_call_into_python, void* func_addr, st
}
#endif
// This is kind of hacky: we release the use of these right now,
// and then expect that everything else will not clobber any of the arguments.
// Naively moving this below the reg spilling will always spill the arguments;
// but sometimes you need to do that if the argument lives past the call.
// Hacky, but the right way to do it requires a bit of reworking so that it can
// spill but keep its current use.
for
(
int
i
=
0
;
i
<
args
.
size
();
i
++
)
{
args
[
i
].
setDoneUsing
();
}
// Spill caller-saved registers:
for
(
auto
check_reg
:
caller_save_registers
)
{
// check_reg.dump();
...
...
@@ -488,6 +583,17 @@ RewriterVarUsage2 Rewriter2::call(bool can_call_into_python, void* func_addr, st
break
;
}
}
for
(
int
i
=
0
;
i
<
args
.
size
();
i
++
)
{
if
(
args
[
i
].
var
==
var
)
{
if
(
var
->
num_uses
==
1
)
{
// If we hold the only usage of this arg var, we are
// going to kill all of its usages soon anyway,
// so we have no need to spill it.
need_to_spill
=
false
;
}
break
;
}
}
if
(
need_to_spill
)
{
if
(
check_reg
.
type
==
Location
::
Register
)
{
...
...
@@ -502,6 +608,15 @@ RewriterVarUsage2 Rewriter2::call(bool can_call_into_python, void* func_addr, st
}
}
// We call setDoneUsing after spilling because when we release these,
// we might release a pointer to an array in the scratch space allocated
// with _allocate. If we do that before spilling, we might spill into that
// scratch space.
for
(
int
i
=
0
;
i
<
args
.
size
();
i
++
)
{
args
[
i
].
setDoneUsing
();
}
#ifndef NDEBUG
for
(
const
auto
&
p
:
vars_by_location
)
{
Location
l
=
p
.
first
;
...
...
@@ -558,7 +673,7 @@ void Rewriter2::commit() {
assert
(
vars_by_location
.
size
()
==
0
);
rewrite
->
commit
(
0
,
this
);
rewrite
->
commit
(
decision_path
,
this
);
}
void
Rewriter2
::
finishAssembly
(
int
continue_offset
)
{
...
...
@@ -568,29 +683,32 @@ void Rewriter2::finishAssembly(int continue_offset) {
}
void
Rewriter2
::
commitReturning
(
RewriterVarUsage2
usage
)
{
assert
(
usage
.
var
->
isInLocation
(
getReturnDestination
()));
/*
Location l = usage.var->location;
Location expected = getReturnDestination();
if (l != expected) {
assert(l.type == Location::Register);
assert(expected.type == Location::Register);
assembler->mov(l.asRegister(), expected.asRegister());
}
*/
// assert(usage.var->isInLocation(getReturnDestination()));
usage
.
var
->
getInReg
(
getReturnDestination
());
usage
.
setDoneUsing
();
commit
();
}
void
Rewriter2
::
addDecision
(
int
way
)
{
assert
(
ndecisions
<
60
);
ndecisions
++
;
decision_path
=
(
decision_path
<<
1
)
|
way
;
}
void
Rewriter2
::
addDependenceOn
(
ICInvalidator
&
invalidator
)
{
rewrite
->
addDependenceOn
(
invalidator
);
}
void
Rewriter2
::
kill
(
RewriterVar2
*
var
)
{
for
(
RewriterVarUsage2
&
scratch_range_usage
:
var
->
scratch_range
)
{
// Should be the only usage for this particular var (we
// hold the only usage) so it should cause the array to
// be deallocated.
scratch_range_usage
.
setDoneUsing
();
}
var
->
scratch_range
.
clear
();
for
(
Location
l
:
var
->
locations
)
{
assert
(
vars_by_location
[
l
]
==
var
);
vars_by_location
.
erase
(
l
);
...
...
@@ -601,22 +719,121 @@ Location Rewriter2::allocScratch() {
int
scratch_bytes
=
rewrite
->
getScratchBytes
();
for
(
int
i
=
0
;
i
<
scratch_bytes
;
i
+=
8
)
{
Location
l
(
Location
::
Scratch
,
i
);
if
(
vars_by_location
.
count
(
l
)
==
0
)
if
(
vars_by_location
.
count
(
l
)
==
0
)
{
return
l
;
}
}
RELEASE_ASSERT
(
0
,
"Using all %d bytes of scratch!"
,
scratch_bytes
);
}
std
::
pair
<
RewriterVarUsage2
,
int
>
Rewriter2
::
_allocate
(
int
n
)
{
assert
(
n
>=
1
);
int
scratch_bytes
=
rewrite
->
getScratchBytes
();
int
consec
=
0
;
for
(
int
i
=
0
;
i
<
scratch_bytes
;
i
+=
8
)
{
Location
l
(
Location
::
Scratch
,
i
);
if
(
vars_by_location
.
count
(
l
)
==
0
)
{
consec
++
;
if
(
consec
==
n
)
{
int
a
=
i
/
8
-
n
+
1
;
int
b
=
i
/
8
;
assembler
::
Register
r
=
allocReg
(
Location
::
any
());
// TODO should be a LEA instruction
// In fact, we could do something like we do for constants and only load
// this when necessary, so it won't spill. Is that worth?
assembler
->
mov
(
assembler
::
RBP
,
r
);
assembler
->
add
(
assembler
::
Immediate
(
8
*
a
+
rewrite
->
getScratchRbpOffset
()),
r
);
RewriterVarUsage2
usage
=
createNewVar
(
r
);
for
(
int
j
=
a
;
j
<=
b
;
j
++
)
{
Location
m
(
Location
::
Scratch
,
j
*
8
);
RewriterVarUsage2
placeholder
=
createNewVar
(
m
);
usage
.
var
->
scratch_range
.
push_back
(
std
::
move
(
placeholder
));
}
return
std
::
make_pair
(
std
::
move
(
usage
),
a
);
}
}
else
{
consec
=
0
;
}
}
RELEASE_ASSERT
(
0
,
"Using all %d bytes of scratch!"
,
scratch_bytes
);
}
RewriterVarUsage2
Rewriter2
::
allocate
(
int
n
)
{
return
_allocate
(
n
).
first
;
}
RewriterVarUsage2
Rewriter2
::
allocateAndCopy
(
RewriterVarUsage2
array_ptr
,
int
n
)
{
// TODO smart register allocation
array_ptr
.
assertValid
();
std
::
pair
<
RewriterVarUsage2
,
int
>
allocation
=
_allocate
(
n
);
int
offset
=
allocation
.
second
;
assembler
::
Register
tmp
=
allocReg
(
Location
::
any
());
assembler
::
Register
src_ptr
=
array_ptr
.
var
->
getInReg
();
assert
(
tmp
!=
src_ptr
);
// TODO how to ensure this?
for
(
int
i
=
0
;
i
<
n
;
i
++
)
{
assembler
->
mov
(
assembler
::
Indirect
(
src_ptr
,
8
*
i
),
tmp
);
assembler
->
mov
(
tmp
,
assembler
::
Indirect
(
assembler
::
RBP
,
8
*
(
offset
+
i
)
+
rewrite
->
getScratchRbpOffset
()));
}
array_ptr
.
setDoneUsing
();
return
std
::
move
(
allocation
.
first
);
}
RewriterVarUsage2
Rewriter2
::
allocateAndCopyPlus1
(
RewriterVarUsage2
first_elem
,
RewriterVarUsage2
rest_ptr
,
int
n_rest
)
{
first_elem
.
assertValid
();
if
(
n_rest
>
0
)
rest_ptr
.
assertValid
();
else
assert
(
rest_ptr
.
isDoneUsing
());
std
::
pair
<
RewriterVarUsage2
,
int
>
allocation
=
_allocate
(
n_rest
+
1
);
int
offset
=
allocation
.
second
;
assembler
::
Register
tmp
=
first_elem
.
var
->
getInReg
();
assembler
->
mov
(
tmp
,
assembler
::
Indirect
(
assembler
::
RBP
,
8
*
offset
+
rewrite
->
getScratchRbpOffset
()));
if
(
n_rest
>
0
)
{
assembler
::
Register
src_ptr
=
rest_ptr
.
var
->
getInReg
();
// TODO if this triggers we'll need a way to allocate two distinct registers
assert
(
tmp
!=
src_ptr
);
for
(
int
i
=
0
;
i
<
n_rest
;
i
++
)
{
assembler
->
mov
(
assembler
::
Indirect
(
src_ptr
,
8
*
i
),
tmp
);
assembler
->
mov
(
tmp
,
assembler
::
Indirect
(
assembler
::
RBP
,
8
*
(
offset
+
i
+
1
)
+
rewrite
->
getScratchRbpOffset
()));
}
rest_ptr
.
setDoneUsing
();
}
first_elem
.
setDoneUsing
();
return
std
::
move
(
allocation
.
first
);
}
assembler
::
Indirect
Rewriter2
::
indirectFor
(
Location
l
)
{
assert
(
l
.
type
==
Location
::
Scratch
);
assert
(
l
.
type
==
Location
::
Scratch
||
l
.
type
==
Location
::
Stack
);
// TODO it can sometimes be more efficient to do RSP-relative addressing?
int
rbp_offset
=
rewrite
->
getScratchRbpOffset
()
+
l
.
scratch_offset
;
return
assembler
::
Indirect
(
assembler
::
RBP
,
rbp_offset
);
if
(
l
.
type
==
Location
::
Scratch
)
// TODO it can sometimes be more efficient to do RSP-relative addressing?
return
assembler
::
Indirect
(
assembler
::
RBP
,
rewrite
->
getScratchRbpOffset
()
+
l
.
scratch_offset
);
else
return
assembler
::
Indirect
(
assembler
::
RSP
,
l
.
stack_offset
);
}
void
Rewriter2
::
spillRegister
(
assembler
::
Register
reg
)
{
assert
(
done_guarding
);
// Don't spill a register than an input argument is in, unless
// we are done guarding (in which case `args` will be empty)
for
(
int
i
=
0
;
i
<
args
.
size
();
i
++
)
{
assert
(
!
args
[
i
]
->
isInLocation
(
Location
(
reg
)));
}
RewriterVar2
*
var
=
vars_by_location
[
reg
];
assert
(
var
);
...
...
@@ -662,7 +879,7 @@ assembler::Register Rewriter2::allocReg(Location dest) {
if
(
vars_by_location
.
count
(
reg
)
==
0
)
return
reg
;
}
RELEASE_ASSERT
(
0
,
"couldn't find a reg to allocate and haven't added spilling"
);
return
allocReg
(
assembler
::
R15
);
// seem as fine as any
}
else
if
(
dest
.
type
==
Location
::
Register
)
{
assembler
::
Register
reg
(
dest
.
regnum
);
...
...
@@ -690,7 +907,7 @@ void Rewriter2::addLocationToVar(RewriterVar2* var, Location l) {
void
Rewriter2
::
removeLocationFromVar
(
RewriterVar2
*
var
,
Location
l
)
{
assert
(
var
->
isInLocation
(
l
));
assert
(
vars_by_location
[
l
]
=
var
);
assert
(
vars_by_location
[
l
]
=
=
var
);
vars_by_location
.
erase
(
l
);
var
->
locations
.
erase
(
l
);
...
...
@@ -710,7 +927,7 @@ TypeRecorder* Rewriter2::getTypeRecorder() {
Rewriter2
::
Rewriter2
(
ICSlotRewrite
*
rewrite
,
int
num_args
,
const
std
::
vector
<
int
>&
live_outs
)
:
rewrite
(
rewrite
),
assembler
(
rewrite
->
getAssembler
()),
return_location
(
rewrite
->
returnRegister
()),
done_guarding
(
false
)
{
done_guarding
(
false
)
,
ndecisions
(
0
),
decision_path
(
1
)
{
// assembler->trap();
for
(
int
i
=
0
;
i
<
num_args
;
i
++
)
{
...
...
@@ -718,6 +935,7 @@ Rewriter2::Rewriter2(ICSlotRewrite* rewrite, int num_args, const std::vector<int
RewriterVar2
*
var
=
new
RewriterVar2
(
this
,
l
);
vars_by_location
[
l
]
=
var
;
var
->
incUse
();
args
.
push_back
(
var
);
}
...
...
@@ -747,11 +965,10 @@ Rewriter2::Rewriter2(ICSlotRewrite* rewrite, int num_args, const std::vector<int
}
RewriterVar2
*&
var
=
vars_by_location
[
l
];
if
(
var
)
{
var
->
incUse
();
}
else
{
if
(
!
var
)
{
var
=
new
RewriterVar2
(
this
,
l
);
}
var
->
incUse
();
this
->
live_outs
.
push_back
(
var
);
this
->
live_out_regs
.
push_back
(
dwarf_regnum
);
...
...
@@ -770,4 +987,8 @@ Rewriter2* Rewriter2::createRewriter(void* rtn_addr, int num_args, const char* d
return
new
Rewriter2
(
ic
->
startRewrite
(
debug_name
),
num_args
,
ic
->
getLiveOuts
());
}
RewriterVarUsage2
RewriterVarUsage2
::
addUse
()
{
return
RewriterVarUsage2
(
var
);
}
}
src/asm_writing/rewriter2.h
View file @
fc111bc5
...
...
@@ -36,7 +36,7 @@ public:
enum
LocationType
:
uint8_t
{
Register
,
XMMRegister
,
//
Stack,
Stack
,
Scratch
,
// stack location, relative to the scratch start
// For representing constants that fit in 32-bits, that can be encoded as immediates
...
...
@@ -152,13 +152,18 @@ public:
#endif
void
setDoneUsing
();
bool
isDoneUsing
();
void
ensureDoneUsing
();
// RewriterVarUsage2 addUse() { return var->addUse(); }
RewriterVarUsage2
addUse
();
void
addGuard
(
uint64_t
val
);
void
addGuardNotEq
(
uint64_t
val
);
void
addAttrGuard
(
int
offset
,
uint64_t
val
);
RewriterVarUsage2
getAttr
(
int
offset
,
KillFlag
kill
,
Location
loc
=
Location
::
any
());
void
setAttr
(
int
offset
,
RewriterVarUsage2
other
);
RewriterVarUsage2
cmp
(
AST_TYPE
::
AST_TYPE
cmp_type
,
RewriterVarUsage2
other
,
Location
loc
=
Location
::
any
());
RewriterVarUsage2
toBool
(
KillFlag
kill
,
Location
loc
=
Location
::
any
());
friend
class
Rewriter2
;
};
...
...
@@ -174,6 +179,10 @@ private:
std
::
unordered_set
<
Location
>
locations
;
bool
isInLocation
(
Location
l
);
// Indicates that this value is a pointer to a fixed-size range in the scratch space.
// This is a vector of variable usages that keep the range allocated.
std
::
vector
<
RewriterVarUsage2
>
scratch_range
;
// Gets a copy of this variable in a register, spilling/reloading if necessary.
// TODO have to be careful with the result since the interface doesn't guarantee
// that the register will still contain your value when you go to use it
...
...
@@ -189,7 +198,7 @@ public:
void
incUse
();
void
decUse
();
RewriterVar2
(
Rewriter2
*
rewriter
,
Location
location
)
:
rewriter
(
rewriter
),
num_uses
(
1
)
{
RewriterVar2
(
Rewriter2
*
rewriter
,
Location
location
)
:
rewriter
(
rewriter
),
num_uses
(
0
)
{
assert
(
rewriter
);
locations
.
insert
(
location
);
}
...
...
@@ -239,6 +248,11 @@ private:
void
finishAssembly
(
int
continue_offset
)
override
;
std
::
pair
<
RewriterVarUsage2
,
int
>
_allocate
(
int
n
);
int
ndecisions
;
uint64_t
decision_path
;
public:
// This should be called exactly once for each argument
RewriterVarUsage2
getArg
(
int
argnum
);
...
...
@@ -255,6 +269,10 @@ public:
RewriterVarUsage2
call
(
bool
can_call_into_python
,
void
*
func_addr
,
std
::
vector
<
RewriterVarUsage2
>
args
);
RewriterVarUsage2
call
(
bool
can_call_into_python
,
void
*
func_addr
,
RewriterVarUsage2
arg0
);
RewriterVarUsage2
call
(
bool
can_call_into_python
,
void
*
func_addr
,
RewriterVarUsage2
arg0
,
RewriterVarUsage2
arg1
);
RewriterVarUsage2
allocate
(
int
n
);
RewriterVarUsage2
allocateAndCopy
(
RewriterVarUsage2
array
,
int
n
);
RewriterVarUsage2
allocateAndCopyPlus1
(
RewriterVarUsage2
first_elem
,
RewriterVarUsage2
rest
,
int
n_rest
);
void
deallocateStack
(
int
nbytes
);
void
commit
();
void
commitReturning
(
RewriterVarUsage2
rtn
);
...
...
@@ -263,6 +281,8 @@ public:
static
Rewriter2
*
createRewriter
(
void
*
rtn_addr
,
int
num_args
,
const
char
*
debug_name
);
void
addDecision
(
int
way
);
friend
class
RewriterVar2
;
friend
class
RewriterVarUsage2
;
};
...
...
src/core/cfg.cpp
View file @
fc111bc5
...
...
@@ -1812,7 +1812,7 @@ CFG* computeCFG(SourceInfo* source, std::vector<AST_stmt*> body) {
if
(
source
->
ast
->
type
==
AST_TYPE
::
ClassDef
)
{
// A classdef always starts with "__module__ = __name__"
Box
*
module_name
=
source
->
parent_module
->
getattr
(
"__name__"
,
NULL
,
NULL
);
Box
*
module_name
=
source
->
parent_module
->
getattr
(
"__name__"
,
NULL
);
assert
(
module_name
->
cls
==
str_cls
);
AST_Assign
*
module_assign
=
new
AST_Assign
();
module_assign
->
targets
.
push_back
(
makeName
(
"__module__"
,
AST_TYPE
::
Store
));
...
...
src/core/types.h
View file @
fc111bc5
...
...
@@ -54,6 +54,11 @@ struct ArgPassSpec {
int
totalPassed
()
{
return
num_args
+
num_keywords
+
(
has_starargs
?
1
:
0
)
+
(
has_kwargs
?
1
:
0
);
}
uintptr_t
asInt
()
const
{
return
*
reinterpret_cast
<
const
uintptr_t
*>
(
this
);
}
void
dump
()
{
printf
(
"(has_starargs=%s, has_kwargs=%s, num_keywords=%d, num_args=%d)
\n
"
,
has_starargs
?
"true"
:
"false"
,
has_kwargs
?
"true"
:
"false"
,
num_keywords
,
num_args
);
}
};
static_assert
(
sizeof
(
ArgPassSpec
)
<=
sizeof
(
void
*
),
"ArgPassSpec doesn't fit in register!"
);
...
...
@@ -233,7 +238,7 @@ public:
};
typedef
std
::
vector
<
CompiledFunction
*>
FunctionList
;
class
CallRewriteArgs
;
class
CallRewriteArgs
2
;
class
CLFunction
{
public:
int
num_args
;
...
...
@@ -249,7 +254,7 @@ public:
// of the normal dispatch through the functionlist.
// This can be used to implement functions which know how to rewrite themselves,
// such as typeCall.
typedef
Box
*
(
*
InternalCallable
)(
BoxedFunction
*
,
CallRewriteArgs
*
,
ArgPassSpec
,
Box
*
,
Box
*
,
Box
*
,
Box
**
,
typedef
Box
*
(
*
InternalCallable
)(
BoxedFunction
*
,
CallRewriteArgs
2
*
,
ArgPassSpec
,
Box
*
,
Box
*
,
Box
*
,
Box
**
,
const
std
::
vector
<
const
std
::
string
*>*
);
InternalCallable
internal_callable
=
NULL
;
...
...
@@ -372,7 +377,6 @@ private:
class
SetattrRewriteArgs2
;
class
GetattrRewriteArgs
;
class
GetattrRewriteArgs2
;
class
DelattrRewriteArgs2
;
...
...
@@ -404,8 +408,8 @@ public:
this
->
setattr
(
attr
,
val
,
NULL
);
}
Box
*
getattr
(
const
std
::
string
&
attr
,
GetattrRewriteArgs
*
rewrite_args
,
GetattrRewriteArgs
2
*
rewrite_args2
);
Box
*
getattr
(
const
std
::
string
&
attr
)
{
return
getattr
(
attr
,
NULL
,
NULL
);
}
Box
*
getattr
(
const
std
::
string
&
attr
,
GetattrRewriteArgs2
*
rewrite_args2
);
Box
*
getattr
(
const
std
::
string
&
attr
)
{
return
getattr
(
attr
,
NULL
);
}
void
delattr
(
const
std
::
string
&
attr
,
DelattrRewriteArgs2
*
rewrite_args
);
};
...
...
src/runtime/builtin_modules/builtins.cpp
View file @
fc111bc5
...
...
@@ -56,7 +56,7 @@ extern "C" Box* dir(Box* obj) {
}
// If __dict__ is present use its keys and add the reset below
Box
*
obj_dict
=
getattr_internal
(
obj
,
"__dict__"
,
false
,
true
,
nullptr
,
nullptr
);
Box
*
obj_dict
=
getattr_internal
(
obj
,
"__dict__"
,
false
,
true
,
nullptr
);
if
(
obj_dict
&&
obj_dict
->
cls
==
dict_cls
)
{
result
=
new
BoxedList
();
for
(
auto
&
kv
:
static_cast
<
BoxedDict
*>
(
obj_dict
)
->
d
)
{
...
...
@@ -326,7 +326,7 @@ Box* getattrFunc(Box* obj, Box* _str, Box* default_value) {
}
BoxedString
*
str
=
static_cast
<
BoxedString
*>
(
_str
);
Box
*
rtn
=
getattr_internal
(
obj
,
str
->
s
,
true
,
true
,
NULL
,
NULL
);
Box
*
rtn
=
getattr_internal
(
obj
,
str
->
s
,
true
,
true
,
NULL
);
if
(
!
rtn
)
{
if
(
default_value
)
...
...
@@ -345,7 +345,7 @@ Box* hasattr(Box* obj, Box* _str) {
}
BoxedString
*
str
=
static_cast
<
BoxedString
*>
(
_str
);
Box
*
attr
=
getattr_internal
(
obj
,
str
->
s
,
true
,
true
,
NULL
,
NULL
);
Box
*
attr
=
getattr_internal
(
obj
,
str
->
s
,
true
,
true
,
NULL
);
Box
*
rtn
=
attr
?
True
:
False
;
return
rtn
;
...
...
src/runtime/objmodel.cpp
View file @
fc111bc5
This source diff could not be displayed because it is too large. You can
view the blob
instead.
src/runtime/objmodel.h
View file @
fc111bc5
...
...
@@ -81,30 +81,29 @@ extern "C" void assertFail(BoxedModule* inModule, Box* msg);
extern
"C"
bool
isSubclass
(
BoxedClass
*
child
,
BoxedClass
*
parent
);
extern
"C"
BoxedClosure
*
createClosure
(
BoxedClosure
*
parent_closure
);
class
BinopRewriteArgs
;
extern
"C"
Box
*
binopInternal
(
Box
*
lhs
,
Box
*
rhs
,
int
op_type
,
bool
inplace
,
BinopRewriteArgs
*
rewrite_args
);
class
BinopRewriteArgs
2
;
extern
"C"
Box
*
binopInternal
(
Box
*
lhs
,
Box
*
rhs
,
int
op_type
,
bool
inplace
,
BinopRewriteArgs
2
*
rewrite_args
);
Box
*
typeCallInternal
(
BoxedFunction
*
f
,
CallRewriteArgs
*
rewrite_args
,
ArgPassSpec
argspec
,
Box
*
arg1
,
Box
*
arg2
,
class
CallRewriteArgs2
;
Box
*
typeCallInternal
(
BoxedFunction
*
f
,
CallRewriteArgs2
*
rewrite_args
,
ArgPassSpec
argspec
,
Box
*
arg1
,
Box
*
arg2
,
Box
*
arg3
,
Box
**
args
,
const
std
::
vector
<
const
std
::
string
*>*
keyword_names
);
class
CallRewriteArgs
;
enum
LookupScope
{
CLASS_ONLY
=
1
,
INST_ONLY
=
2
,
CLASS_OR_INST
=
3
,
};
extern
"C"
Box
*
callattrInternal
(
Box
*
obj
,
const
std
::
string
*
attr
,
LookupScope
,
CallRewriteArgs
*
rewrite_args
,
extern
"C"
Box
*
callattrInternal
(
Box
*
obj
,
const
std
::
string
*
attr
,
LookupScope
,
CallRewriteArgs
2
*
rewrite_args
,
ArgPassSpec
argspec
,
Box
*
arg1
,
Box
*
arg2
,
Box
*
arg3
,
Box
**
args
,
const
std
::
vector
<
const
std
::
string
*>*
keyword_names
);
extern
"C"
void
delattr_internal
(
Box
*
obj
,
const
std
::
string
&
attr
,
bool
allow_custom
,
DelattrRewriteArgs2
*
rewrite_args
);
struct
CompareRewriteArgs
;
Box
*
compareInternal
(
Box
*
lhs
,
Box
*
rhs
,
int
op_type
,
CompareRewriteArgs
*
rewrite_args
);
struct
CompareRewriteArgs
2
;
Box
*
compareInternal
(
Box
*
lhs
,
Box
*
rhs
,
int
op_type
,
CompareRewriteArgs
2
*
rewrite_args
);
Box
*
getattr_internal
(
Box
*
obj
,
const
std
::
string
&
attr
,
bool
check_cls
,
bool
allow_custom
,
GetattrRewriteArgs
*
rewrite_args
,
GetattrRewriteArgs
2
*
rewrite_args2
);
GetattrRewriteArgs2
*
rewrite_args2
);
Box
*
typeLookup
(
BoxedClass
*
cls
,
const
std
::
string
&
attr
,
GetattrRewriteArgs
*
rewrite_args
,
GetattrRewriteArgs2
*
rewrite_args2
);
Box
*
typeLookup
(
BoxedClass
*
cls
,
const
std
::
string
&
attr
,
GetattrRewriteArgs2
*
rewrite_args2
);
extern
"C"
void
raiseAttributeErrorStr
(
const
char
*
typeName
,
const
char
*
attr
)
__attribute__
((
__noreturn__
));
extern
"C"
void
raiseAttributeError
(
Box
*
obj
,
const
char
*
attr
)
__attribute__
((
__noreturn__
));
...
...
@@ -114,7 +113,7 @@ Box* typeCall(Box*, BoxedList*);
Box
*
typeNew
(
Box
*
,
Box
*
);
bool
isUserDefined
(
BoxedClass
*
cls
);
Box
*
callCLFunc
(
CLFunction
*
f
,
CallRewriteArgs
*
rewrite_args
,
int
num_output_args
,
BoxedClosure
*
closure
,
Box
*
callCLFunc
(
CLFunction
*
f
,
CallRewriteArgs
2
*
rewrite_args
,
int
num_output_args
,
BoxedClosure
*
closure
,
BoxedGenerator
*
generator
,
Box
*
oarg1
,
Box
*
oarg2
,
Box
*
oarg3
,
Box
**
oargs
);
}
#endif
src/runtime/types.cpp
View file @
fc111bc5
...
...
@@ -84,7 +84,7 @@ extern "C" BoxedFunction::BoxedFunction(CLFunction* f)
// this->giveAttr("__name__", boxString(&f->source->ast->name));
this
->
giveAttr
(
"__name__"
,
boxString
(
f
->
source
->
getName
()));
Box
*
modname
=
f
->
source
->
parent_module
->
getattr
(
"__name__"
,
NULL
,
NULL
);
Box
*
modname
=
f
->
source
->
parent_module
->
getattr
(
"__name__"
,
NULL
);
this
->
giveAttr
(
"__module__"
,
modname
);
}
...
...
@@ -110,7 +110,7 @@ extern "C" BoxedFunction::BoxedFunction(CLFunction* f, std::initializer_list<Box
// this->giveAttr("__name__", boxString(&f->source->ast->name));
this
->
giveAttr
(
"__name__"
,
boxString
(
f
->
source
->
getName
()));
Box
*
modname
=
f
->
source
->
parent_module
->
getattr
(
"__name__"
,
NULL
,
NULL
);
Box
*
modname
=
f
->
source
->
parent_module
->
getattr
(
"__name__"
,
NULL
);
this
->
giveAttr
(
"__module__"
,
modname
);
}
...
...
@@ -513,7 +513,7 @@ Box* objectNew(BoxedClass* cls, BoxedTuple* args) {
if
(
args
->
elts
.
size
()
!=
0
)
{
// TODO slow
if
(
typeLookup
(
cls
,
"__init__"
,
NULL
,
NULL
)
==
typeLookup
(
object_cls
,
"__init__"
,
NULL
,
NULL
))
if
(
typeLookup
(
cls
,
"__init__"
,
NULL
)
==
typeLookup
(
object_cls
,
"__init__"
,
NULL
))
raiseExcHelper
(
TypeError
,
"object.__new__() takes no parameters"
);
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment